]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/boot/dtc-src/flattree.c
Merge branches 'release', 'misc' and 'misc-2.6.25' into release
[linux-2.6-omap-h63xx.git] / arch / powerpc / boot / dtc-src / flattree.c
1 /*
2  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3  *
4  *
5  * 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.
14  *
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
19  */
20
21 #include "dtc.h"
22
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
28 #define FTF_STRUCTSIZE  0x20
29 #define FTF_NOPS        0x40
30
31 static struct version_info {
32         int version;
33         int last_comp_version;
34         int hdr_size;
35         int flags;
36 } version_table[] = {
37         {1, 1, FDT_V1_SIZE,
38          FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
39         {2, 1, FDT_V2_SIZE,
40          FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
41         {3, 1, FDT_V3_SIZE,
42          FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
43         {16, 16, FDT_V3_SIZE,
44          FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
45         {17, 16, FDT_V17_SIZE,
46          FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
47 };
48
49 struct emitter {
50         void (*cell)(void *, cell_t);
51         void (*string)(void *, char *, int);
52         void (*align)(void *, int);
53         void (*data)(void *, struct data);
54         void (*beginnode)(void *, const char *);
55         void (*endnode)(void *, const char *);
56         void (*property)(void *, const char *);
57 };
58
59 static 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
66 static 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
77 static void bin_emit_align(void *e, int a)
78 {
79         struct data *dtbuf = e;
80
81         *dtbuf = data_append_align(*dtbuf, a);
82 }
83
84 static 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
91 static void bin_emit_beginnode(void *e, const char *label)
92 {
93         bin_emit_cell(e, FDT_BEGIN_NODE);
94 }
95
96 static void bin_emit_endnode(void *e, const char *label)
97 {
98         bin_emit_cell(e, FDT_END_NODE);
99 }
100
101 static void bin_emit_property(void *e, const char *label)
102 {
103         bin_emit_cell(e, FDT_PROP);
104 }
105
106 static struct emitter bin_emitter = {
107         .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,
113         .property = bin_emit_property,
114 };
115
116 static void emit_label(FILE *f, const char *prefix, const char *label)
117 {
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
123 static void emit_offset_label(FILE *f, const 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
129 static void asm_emit_cell(void *e, cell_t val)
130 {
131         FILE *f = e;
132
133         fprintf(f, "\t.long\t0x%x\n", val);
134 }
135
136 static void asm_emit_string(void *e, char *str, int len)
137 {
138         FILE *f = e;
139         char c = 0;
140
141         if (len != 0) {
142                 /* XXX: ewww */
143                 c = str[len];
144                 str[len] = '\0';
145         }
146
147         fprintf(f, "\t.string\t\"%s\"\n", str);
148
149         if (len != 0) {
150                 str[len] = c;
151         }
152 }
153
154 static 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
161 static void asm_emit_data(void *e, struct data d)
162 {
163         FILE *f = e;
164         int off = 0;
165         struct marker *m;
166
167         m = d.markers;
168         while (m) {
169                 if (m->type == LABEL)
170                         emit_offset_label(f, m->ref, m->offset);
171                 m = m->next;
172         }
173
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)) {
181                 fprintf(f, "\t.short\t0x%hx\n",
182                         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
194 static void asm_emit_beginnode(void *e, const char *label)
195 {
196         FILE *f = e;
197
198         if (label) {
199                 fprintf(f, "\t.globl\t%s\n", label);
200                 fprintf(f, "%s:\n", label);
201         }
202         fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
203 }
204
205 static void asm_emit_endnode(void *e, const char *label)
206 {
207         FILE *f = e;
208
209         fprintf(f, "\t.long\tFDT_END_NODE\n");
210         if (label) {
211                 fprintf(f, "\t.globl\t%s_end\n", label);
212                 fprintf(f, "%s_end:\n", label);
213         }
214 }
215
216 static void asm_emit_property(void *e, const char *label)
217 {
218         FILE *f = e;
219
220         if (label) {
221                 fprintf(f, "\t.globl\t%s\n", label);
222                 fprintf(f, "%s:\n", label);
223         }
224         fprintf(f, "\t.long\tFDT_PROP\n");
225 }
226
227 static struct emitter asm_emitter = {
228         .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,
234         .property = asm_emit_property,
235 };
236
237 static int stringtable_insert(struct data *d, const char *str)
238 {
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);
249         return i;
250 }
251
252 static 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
260         emit->beginnode(etarget, tree->label);
261
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
277                 emit->property(etarget, prop->label);
278                 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) {
289                 emit->property(etarget, NULL);
290                 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);
297                 emit->align(etarget, sizeof(cell_t));
298         }
299
300         for_each_child(tree, child) {
301                 flatten_tree(child, emit, etarget, strbuf, vi);
302         }
303
304         emit->endnode(etarget, tree->label);
305 }
306
307 static 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;
312         static struct fdt_reserve_entry null_re = {0,0};
313         int    j;
314
315         for (re = reservelist; re; re = re->next) {
316                 d = data_append_re(d, &re->re);
317         }
318         /*
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         }
324
325         return d;
326 }
327
328 static 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)
332 {
333         int reserve_off;
334
335         reservesize += sizeof(struct fdt_reserve_entry);
336
337         memset(fdt, 0xff, sizeof(*fdt));
338
339         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);
342
343         /* Reserve map should be doubleword aligned */
344         reserve_off = ALIGN(vi->hdr_size, 8);
345
346         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
349                                           + dtsize);
350         fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize);
351
352         if (vi->flags & FTF_BOOTCPUID)
353                 fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys);
354         if (vi->flags & FTF_STRTABSIZE)
355                 fdt->size_dt_strings = cpu_to_be32(strsize);
356         if (vi->flags & FTF_STRUCTSIZE)
357                 fdt->size_dt_struct = cpu_to_be32(dtsize);
358 }
359
360 void dt_to_blob(FILE *f, struct boot_info *bi, int version,
361                 int boot_cpuid_phys)
362 {
363         struct version_info *vi = NULL;
364         int i;
365         struct data blob       = empty_data;
366         struct data reservebuf = empty_data;
367         struct data dtbuf      = empty_data;
368         struct data strbuf     = empty_data;
369         struct fdt_header fdt;
370         int padlen = 0;
371
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
379         flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
380         bin_emit_cell(&dtbuf, FDT_END);
381
382         reservebuf = flatten_reserve_list(bi->reservelist, vi);
383
384         /* Make header */
385         make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
386                         boot_cpuid_phys);
387
388         /*
389          * If the user asked for more space than is used, adjust the totalsize.
390          */
391         if (minsize > 0) {
392                 padlen = minsize - be32_to_cpu(fdt.totalsize);
393                 if ((padlen < 0) && (quiet < 1))
394                         fprintf(stderr,
395                                 "Warning: blob size %d >= minimum size %d\n",
396                                 be32_to_cpu(fdt.totalsize), minsize);
397         }
398
399         if (padsize > 0)
400                 padlen = padsize;
401
402         if (padlen > 0) {
403                 int tsize = be32_to_cpu(fdt.totalsize);
404                 tsize += padlen;
405                 fdt.totalsize = cpu_to_be32(tsize);
406         }
407
408         /*
409          * 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          */
413         blob = data_append_data(blob, &fdt, sizeof(fdt));
414         blob = data_append_align(blob, 8);
415         blob = data_merge(blob, reservebuf);
416         blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
417         blob = data_merge(blob, dtbuf);
418         blob = data_merge(blob, strbuf);
419
420         /*
421          * If the user asked for more space than is used, pad out the blob.
422          */
423         if (padlen > 0)
424                 blob = data_append_zeroes(blob, padlen);
425
426         fwrite(blob.val, blob.len, 1, f);
427
428         if (ferror(f))
429                 die("Error writing device tree blob: %s\n", strerror(errno));
430
431         /*
432          * data_merge() frees the right-hand element so only the blob
433          * remains to be freed.
434          */
435         data_free(blob);
436 }
437
438 static void dump_stringtable_asm(FILE *f, struct data strbuf)
439 {
440         const char *p;
441         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
452 void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
453 {
454         struct version_info *vi = NULL;
455         int i;
456         struct data strbuf = empty_data;
457         struct reserve_info *re;
458         const char *symprefix = "dt";
459
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");
468         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);
473         fprintf(f, "\n");
474
475         emit_label(f, symprefix, "blob_start");
476         emit_label(f, symprefix, "header");
477         fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
478         fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
479                 symprefix, symprefix);
480         fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
481                 symprefix, symprefix);
482         fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
483                 symprefix, symprefix);
484         fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
485                 symprefix, symprefix);
486         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",
488                 vi->last_comp_version);
489
490         if (vi->flags & FTF_BOOTCPUID)
491                 fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
492                         boot_cpuid_phys);
493
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
498         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
502         /*
503          * Reserve map entries.
504          * Align the reserve map to a doubleword boundary.
505          * Each entry is an (address, size) pair of u64 values.
506          * Always supply a zero-sized temination entry.
507          */
508         asm_emit_align(f, 8);
509         emit_label(f, symprefix, "reserve_map");
510
511         fprintf(f, "/* Memory reserve map from source file */\n");
512
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          */
517         for (re = bi->reservelist; re; re = re->next) {
518                 if (re->label) {
519                         fprintf(f, "\t.globl\t%s\n", re->label);
520                         fprintf(f, "%s:\n", re->label);
521                 }
522                 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
523                         (unsigned int)(re->re.address >> 32),
524                         (unsigned int)(re->re.address & 0xffffffff));
525                 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
526                         (unsigned int)(re->re.size >> 32),
527                         (unsigned int)(re->re.size & 0xffffffff));
528         }
529         for (i = 0; i < reservenum; i++) {
530                 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
531         }
532
533         fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
534
535         emit_label(f, symprefix, "struct_start");
536         flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
537         fprintf(f, "\t.long\tFDT_END\n");
538         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
546         /*
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         }
553         if (padsize > 0) {
554                 fprintf(f, "\t.space\t%d, 0\n", padsize);
555         }
556         emit_label(f, symprefix, "blob_abs_end");
557
558         data_free(strbuf);
559 }
560
561 struct inbuf {
562         char *base, *limit, *ptr;
563 };
564
565 static 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
572 static 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
582 static 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
593 static 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
602 static char *flat_read_string(struct inbuf *inb)
603 {
604         int len = 0;
605         const char *p = inb->ptr;
606         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
623 static 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
640 static char *flat_read_stringtable(struct inbuf *inb, int offset)
641 {
642         const char *p;
643
644         p = inb->base + offset;
645         while (1) {
646                 if (p >= inb->limit || p < inb->base)
647                         die("String offset %d overruns string table\n",
648                             offset);
649
650                 if (*p == '\0')
651                         break;
652
653                 p++;
654         }
655
656         return strdup(inb->base + offset);
657 }
658
659 static struct property *flat_read_property(struct inbuf *dtbuf,
660                                            struct inbuf *strbuf, int flags)
661 {
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
676         return build_property(name, val, NULL);
677 }
678
679
680 static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
681 {
682         struct reserve_info *reservelist = NULL;
683         struct reserve_info *new;
684         const char *p;
685         struct fdt_reserve_entry re;
686
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;
694         while (1) {
695                 flat_read_chunk(inb, &re, sizeof(re));
696                 re.address  = be64_to_cpu(re.address);
697                 re.size = be64_to_cpu(re.size);
698                 if (re.size == 0)
699                         break;
700
701                 new = build_reserve_entry(re.address, re.size, NULL);
702                 reservelist = add_reserve_entry(reservelist, new);
703         }
704
705         return reservelist;
706 }
707
708
709 static char *nodename_from_path(const char *ppath, const char *cpath)
710 {
711         const char *lslash;
712         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
726         if (! strneq(ppath, cpath, plen))
727                 return NULL;
728
729         return strdup(lslash+1);
730 }
731
732 static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
733 static const char UNITCHAR[] = "0123456789abcdef,";
734
735 static int check_node_name(const char *name)
736 {
737         const char *atpos;
738         int basenamelen;
739
740         atpos = strrchr(name, '@');
741
742         if (atpos)
743                 basenamelen = atpos - name;
744         else
745                 basenamelen = strlen(name);
746
747         if (strspn(name, PROPCHAR) < basenamelen)
748                 return -1;
749
750         if (atpos
751             && ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
752                 return -1;
753
754         return basenamelen;
755 }
756
757 static struct node *unflatten_tree(struct inbuf *dtbuf,
758                                    struct inbuf *strbuf,
759                                    const char *parent_path, int flags)
760 {
761         struct node *node;
762         u32 val;
763
764         node = build_node(NULL, NULL);
765
766         if (flags & FTF_FULLPATH) {
767                 node->fullpath = flat_read_string(dtbuf);
768                 node->name = nodename_from_path(parent_path, node->fullpath);
769
770                 if (! node->name)
771                         die("Path \"%s\" is not valid as a child of \"%s\"\n",
772                             node->fullpath, parent_path);
773         } else {
774                 node->name = flat_read_string(dtbuf);
775                 node->fullpath = join_path(parent_path, node->name);
776         }
777
778         node->basenamelen = check_node_name(node->name);
779         if (node->basenamelen < 0) {
780                 fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name);
781         }
782
783         do {
784                 struct property *prop;
785                 struct node *child;
786
787                 val = flat_read_word(dtbuf);
788                 switch (val) {
789                 case FDT_PROP:
790                         if (node->children)
791                                 fprintf(stderr, "Warning: Flat tree input has "
792                                         "subnodes preceding a property.\n");
793                         prop = flat_read_property(dtbuf, strbuf, flags);
794                         add_property(node, prop);
795                         break;
796
797                 case FDT_BEGIN_NODE:
798                         child = unflatten_tree(dtbuf,strbuf, node->fullpath,
799                                                flags);
800                         add_child(node, child);
801                         break;
802
803                 case FDT_END_NODE:
804                         break;
805
806                 case FDT_END:
807                         die("Premature FDT_END in device tree blob\n");
808                         break;
809
810                 case FDT_NOP:
811                         if (!(flags & FTF_NOPS))
812                                 fprintf(stderr, "Warning: NOP tag found in flat tree"
813                                         " version <16\n");
814
815                         /* Ignore */
816                         break;
817
818                 default:
819                         die("Invalid opcode word %08x in device tree blob\n",
820                             val);
821                 }
822         } while (val != FDT_END_NODE);
823
824         return node;
825 }
826
827
828 struct boot_info *dt_from_blob(FILE *f)
829 {
830         u32 magic, totalsize, version, size_str, size_dt;
831         u32 off_dt, off_str, off_mem_rsvmap;
832         int rc;
833         char *blob;
834         struct fdt_header *fdt;
835         char *p;
836         struct inbuf dtbuf, strbuf;
837         struct inbuf memresvbuf;
838         int sizeleft;
839         struct reserve_info *reservelist;
840         struct node *tree;
841         u32 val;
842         int flags = 0;
843
844         rc = fread(&magic, sizeof(magic), 1, f);
845         if (ferror(f))
846                 die("Error reading DT blob magic number: %s\n",
847                     strerror(errno));
848         if (rc < 1) {
849                 if (feof(f))
850                         die("EOF reading DT blob magic number\n");
851                 else
852                         die("Mysterious short read reading magic number\n");
853         }
854
855         magic = be32_to_cpu(magic);
856         if (magic != FDT_MAGIC)
857                 die("Blob has incorrect magic number\n");
858
859         rc = fread(&totalsize, sizeof(totalsize), 1, f);
860         if (ferror(f))
861                 die("Error reading DT blob size: %s\n", strerror(errno));
862         if (rc < 1) {
863                 if (feof(f))
864                         die("EOF reading DT blob size\n");
865                 else
866                         die("Mysterious short read reading blob size\n");
867         }
868
869         totalsize = be32_to_cpu(totalsize);
870         if (totalsize < FDT_V1_SIZE)
871                 die("DT blob size (%d) is too small\n", totalsize);
872
873         blob = xmalloc(totalsize);
874
875         fdt = (struct fdt_header *)blob;
876         fdt->magic = cpu_to_be32(magic);
877         fdt->totalsize = cpu_to_be32(totalsize);
878
879         sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
880         p = blob + sizeof(magic)  + sizeof(totalsize);
881
882         while (sizeleft) {
883                 if (feof(f))
884                         die("EOF before reading %d bytes of DT blob\n",
885                             totalsize);
886
887                 rc = fread(p, 1, sizeleft, f);
888                 if (ferror(f))
889                         die("Error reading DT blob: %s\n",
890                             strerror(errno));
891
892                 sizeleft -= rc;
893                 p += rc;
894         }
895
896         off_dt = be32_to_cpu(fdt->off_dt_struct);
897         off_str = be32_to_cpu(fdt->off_dt_strings);
898         off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap);
899         version = be32_to_cpu(fdt->version);
900
901         fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic);
902         fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize);
903         fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt);
904         fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str);
905         fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap);
906         fprintf(stderr, "\tversion:\t\t0x%x\n", version );
907         fprintf(stderr, "\tlast_comp_version:\t0x%x\n",
908                 be32_to_cpu(fdt->last_comp_version));
909
910         if (off_mem_rsvmap >= totalsize)
911                 die("Mem Reserve structure offset exceeds total size\n");
912
913         if (off_dt >= totalsize)
914                 die("DT structure offset exceeds total size\n");
915
916         if (off_str > totalsize)
917                 die("String table offset exceeds total size\n");
918
919         if (version >= 2)
920                 fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
921                         be32_to_cpu(fdt->boot_cpuid_phys));
922
923         size_str = -1;
924         if (version >= 3) {
925                 size_str = be32_to_cpu(fdt->size_dt_strings);
926                 fprintf(stderr, "\tsize_dt_strings:\t%d\n", size_str);
927                 if (off_str+size_str > totalsize)
928                         die("String table extends past total size\n");
929         }
930
931         if (version >= 17) {
932                 size_dt = be32_to_cpu(fdt->size_dt_struct);
933                 fprintf(stderr, "\tsize_dt_struct:\t\t%d\n", size_dt);
934                 if (off_dt+size_dt > totalsize)
935                         die("Structure block extends past total size\n");
936         }
937
938         if (version < 16) {
939                 flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
940         } else {
941                 flags |= FTF_NOPS;
942         }
943
944         inbuf_init(&memresvbuf,
945                    blob + off_mem_rsvmap, blob + totalsize);
946         inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
947         if (size_str >= 0)
948                 inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
949         else
950                 inbuf_init(&strbuf, blob + off_str, blob + totalsize);
951
952         reservelist = flat_read_mem_reserve(&memresvbuf);
953
954         val = flat_read_word(&dtbuf);
955
956         if (val != FDT_BEGIN_NODE)
957                 die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
958
959         tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
960
961         val = flat_read_word(&dtbuf);
962         if (val != FDT_END)
963                 die("Device tree blob doesn't end with FDT_END\n");
964
965         free(blob);
966
967         return build_boot_info(reservelist, tree);
968 }