Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / arch / powerpc / boot / dtc-src / flattree.c
bloba7cfb843d3342413882a5d3583b725bdfc30e0cd
1 /*
2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
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.
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.
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
21 #include "dtc.h"
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
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},
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 *);
59 static void bin_emit_cell(void *e, cell_t val)
61 struct data *dtbuf = e;
63 *dtbuf = data_append_cell(*dtbuf, val);
66 static void bin_emit_string(void *e, char *str, int len)
68 struct data *dtbuf = e;
70 if (len == 0)
71 len = strlen(str);
73 *dtbuf = data_append_data(*dtbuf, str, len);
74 *dtbuf = data_append_byte(*dtbuf, '\0');
77 static void bin_emit_align(void *e, int a)
79 struct data *dtbuf = e;
81 *dtbuf = data_append_align(*dtbuf, a);
84 static void bin_emit_data(void *e, struct data d)
86 struct data *dtbuf = e;
88 *dtbuf = data_append_data(*dtbuf, d.val, d.len);
91 static void bin_emit_beginnode(void *e, const char *label)
93 bin_emit_cell(e, FDT_BEGIN_NODE);
96 static void bin_emit_endnode(void *e, const char *label)
98 bin_emit_cell(e, FDT_END_NODE);
101 static void bin_emit_property(void *e, const char *label)
103 bin_emit_cell(e, FDT_PROP);
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,
116 static void emit_label(FILE *f, const char *prefix, const char *label)
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);
123 static void emit_offset_label(FILE *f, const char *label, int offset)
125 fprintf(f, "\t.globl\t%s\n", label);
126 fprintf(f, "%s\t= . + %d\n", label, offset);
129 static void asm_emit_cell(void *e, cell_t val)
131 FILE *f = e;
133 fprintf(f, "\t.long\t0x%x\n", val);
136 static void asm_emit_string(void *e, char *str, int len)
138 FILE *f = e;
139 char c = 0;
141 if (len != 0) {
142 /* XXX: ewww */
143 c = str[len];
144 str[len] = '\0';
147 fprintf(f, "\t.string\t\"%s\"\n", str);
149 if (len != 0) {
150 str[len] = c;
154 static void asm_emit_align(void *e, int a)
156 FILE *f = e;
158 fprintf(f, "\t.balign\t%d\n", a);
161 static void asm_emit_data(void *e, struct data d)
163 FILE *f = e;
164 int off = 0;
165 struct marker *m;
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;
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);
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);
186 if ((d.len - off) >= 1) {
187 fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
188 off += 1;
191 assert(off == d.len);
194 static void asm_emit_beginnode(void *e, const char *label)
196 FILE *f = e;
198 if (label) {
199 fprintf(f, "\t.globl\t%s\n", label);
200 fprintf(f, "%s:\n", label);
202 fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
205 static void asm_emit_endnode(void *e, const char *label)
207 FILE *f = e;
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);
216 static void asm_emit_property(void *e, const char *label)
218 FILE *f = e;
220 if (label) {
221 fprintf(f, "\t.globl\t%s\n", label);
222 fprintf(f, "%s:\n", label);
224 fprintf(f, "\t.long\tFDT_PROP\n");
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,
237 static int stringtable_insert(struct data *d, const char *str)
239 int i;
241 /* FIXME: do this more efficiently? */
243 for (i = 0; i < d->len; i++) {
244 if (streq(str, d->val + i))
245 return i;
248 *d = data_append_data(*d, str, strlen(str)+1);
249 return i;
252 static void flatten_tree(struct node *tree, struct emitter *emit,
253 void *etarget, struct data *strbuf,
254 struct version_info *vi)
256 struct property *prop;
257 struct node *child;
258 int seen_name_prop = 0;
260 emit->beginnode(etarget, tree->label);
262 if (vi->flags & FTF_FULLPATH)
263 emit->string(etarget, tree->fullpath, 0);
264 else
265 emit->string(etarget, tree->name, 0);
267 emit->align(etarget, sizeof(cell_t));
269 for_each_property(tree, prop) {
270 int nameoff;
272 if (streq(prop->name, "name"))
273 seen_name_prop = 1;
275 nameoff = stringtable_insert(strbuf, prop->name);
277 emit->property(etarget, prop->label);
278 emit->cell(etarget, prop->val.len);
279 emit->cell(etarget, nameoff);
281 if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
282 emit->align(etarget, 8);
284 emit->data(etarget, prop->val);
285 emit->align(etarget, sizeof(cell_t));
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"));
293 if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
294 emit->align(etarget, 8);
296 emit->string(etarget, tree->name, tree->basenamelen);
297 emit->align(etarget, sizeof(cell_t));
300 for_each_child(tree, child) {
301 flatten_tree(child, emit, etarget, strbuf, vi);
304 emit->endnode(etarget, tree->label);
307 static struct data flatten_reserve_list(struct reserve_info *reservelist,
308 struct version_info *vi)
310 struct reserve_info *re;
311 struct data d = empty_data;
312 static struct fdt_reserve_entry null_re = {0,0};
313 int j;
315 for (re = reservelist; re; re = re->next) {
316 d = data_append_re(d, &re->re);
319 * Add additional reserved slots if the user asked for them.
321 for (j = 0; j < reservenum; j++) {
322 d = data_append_re(d, &null_re);
325 return d;
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)
333 int reserve_off;
335 reservesize += sizeof(struct fdt_reserve_entry);
337 memset(fdt, 0xff, sizeof(*fdt));
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);
343 /* Reserve map should be doubleword aligned */
344 reserve_off = ALIGN(vi->hdr_size, 8);
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);
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);
360 void dt_to_blob(FILE *f, struct boot_info *bi, int version,
361 int boot_cpuid_phys)
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;
372 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
373 if (version_table[i].version == version)
374 vi = &version_table[i];
376 if (!vi)
377 die("Unknown device tree blob version %d\n", version);
379 flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
380 bin_emit_cell(&dtbuf, FDT_END);
382 reservebuf = flatten_reserve_list(bi->reservelist, vi);
384 /* Make header */
385 make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
386 boot_cpuid_phys);
389 * If the user asked for more space than is used, adjust the totalsize.
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);
399 if (padsize > 0)
400 padlen = padsize;
402 if (padlen > 0) {
403 int tsize = be32_to_cpu(fdt.totalsize);
404 tsize += padlen;
405 fdt.totalsize = cpu_to_be32(tsize);
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.
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);
421 * If the user asked for more space than is used, pad out the blob.
423 if (padlen > 0)
424 blob = data_append_zeroes(blob, padlen);
426 fwrite(blob.val, blob.len, 1, f);
428 if (ferror(f))
429 die("Error writing device tree blob: %s\n", strerror(errno));
432 * data_merge() frees the right-hand element so only the blob
433 * remains to be freed.
435 data_free(blob);
438 static void dump_stringtable_asm(FILE *f, struct data strbuf)
440 const char *p;
441 int len;
443 p = strbuf.val;
445 while (p < (strbuf.val + strbuf.len)) {
446 len = strlen(p);
447 fprintf(f, "\t.string \"%s\"\n", p);
448 p += len+1;
452 void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
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";
460 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
461 if (version_table[i].version == version)
462 vi = &version_table[i];
464 if (!vi)
465 die("Unknown device tree blob version %d\n", version);
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");
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);
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);
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);
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);
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.
508 asm_emit_align(f, 8);
509 emit_label(f, symprefix, "reserve_map");
511 fprintf(f, "/* Memory reserve map from source file */\n");
514 * Use .long on high and low halfs of u64s to avoid .quad
515 * as it appears .quad isn't available in some assemblers.
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);
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));
529 for (i = 0; i < reservenum; i++) {
530 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
533 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
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");
540 emit_label(f, symprefix, "strings_start");
541 dump_stringtable_asm(f, strbuf);
542 emit_label(f, symprefix, "strings_end");
544 emit_label(f, symprefix, "blob_end");
547 * If the user asked for more space than is used, pad it out.
549 if (minsize > 0) {
550 fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
551 minsize, symprefix, symprefix);
553 if (padsize > 0) {
554 fprintf(f, "\t.space\t%d, 0\n", padsize);
556 emit_label(f, symprefix, "blob_abs_end");
558 data_free(strbuf);
561 struct inbuf {
562 char *base, *limit, *ptr;
565 static void inbuf_init(struct inbuf *inb, void *base, void *limit)
567 inb->base = base;
568 inb->limit = limit;
569 inb->ptr = inb->base;
572 static void flat_read_chunk(struct inbuf *inb, void *p, int len)
574 if ((inb->ptr + len) > inb->limit)
575 die("Premature end of data parsing flat device tree\n");
577 memcpy(p, inb->ptr, len);
579 inb->ptr += len;
582 static u32 flat_read_word(struct inbuf *inb)
584 u32 val;
586 assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
588 flat_read_chunk(inb, &val, sizeof(val));
590 return be32_to_cpu(val);
593 static void flat_realign(struct inbuf *inb, int align)
595 int off = inb->ptr - inb->base;
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");
602 static char *flat_read_string(struct inbuf *inb)
604 int len = 0;
605 const char *p = inb->ptr;
606 char *str;
608 do {
609 if (p >= inb->limit)
610 die("Premature end of data parsing flat device tree\n");
611 len++;
612 } while ((*p++) != '\0');
614 str = strdup(inb->ptr);
616 inb->ptr += len;
618 flat_realign(inb, sizeof(u32));
620 return str;
623 static struct data flat_read_data(struct inbuf *inb, int len)
625 struct data d = empty_data;
627 if (len == 0)
628 return empty_data;
630 d = data_grow_for(d, len);
631 d.len = len;
633 flat_read_chunk(inb, d.val, len);
635 flat_realign(inb, sizeof(u32));
637 return d;
640 static char *flat_read_stringtable(struct inbuf *inb, int offset)
642 const char *p;
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);
650 if (*p == '\0')
651 break;
653 p++;
656 return strdup(inb->base + offset);
659 static struct property *flat_read_property(struct inbuf *dtbuf,
660 struct inbuf *strbuf, int flags)
662 u32 proplen, stroff;
663 char *name;
664 struct data val;
666 proplen = flat_read_word(dtbuf);
667 stroff = flat_read_word(dtbuf);
669 name = flat_read_stringtable(strbuf, stroff);
671 if ((flags & FTF_VARALIGN) && (proplen >= 8))
672 flat_realign(dtbuf, 8);
674 val = flat_read_data(dtbuf, proplen);
676 return build_property(name, val, NULL);
680 static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
682 struct reserve_info *reservelist = NULL;
683 struct reserve_info *new;
684 const char *p;
685 struct fdt_reserve_entry re;
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.
691 * First pass, count entries.
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;
701 new = build_reserve_entry(re.address, re.size, NULL);
702 reservelist = add_reserve_entry(reservelist, new);
705 return reservelist;
709 static char *nodename_from_path(const char *ppath, const char *cpath)
711 const char *lslash;
712 int plen;
714 lslash = strrchr(cpath, '/');
715 if (! lslash)
716 return NULL;
718 plen = lslash - cpath;
720 if (streq(cpath, "/") && streq(ppath, ""))
721 return "";
723 if ((plen == 0) && streq(ppath, "/"))
724 return strdup(lslash+1);
726 if (! strneq(ppath, cpath, plen))
727 return NULL;
729 return strdup(lslash+1);
732 static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
733 static const char UNITCHAR[] = "0123456789abcdef,";
735 static int check_node_name(const char *name)
737 const char *atpos;
738 int basenamelen;
740 atpos = strrchr(name, '@');
742 if (atpos)
743 basenamelen = atpos - name;
744 else
745 basenamelen = strlen(name);
747 if (strspn(name, PROPCHAR) < basenamelen)
748 return -1;
750 if (atpos
751 && ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
752 return -1;
754 return basenamelen;
757 static struct node *unflatten_tree(struct inbuf *dtbuf,
758 struct inbuf *strbuf,
759 const char *parent_path, int flags)
761 struct node *node;
762 u32 val;
764 node = build_node(NULL, NULL);
766 if (flags & FTF_FULLPATH) {
767 node->fullpath = flat_read_string(dtbuf);
768 node->name = nodename_from_path(parent_path, node->fullpath);
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);
778 node->basenamelen = check_node_name(node->name);
779 if (node->basenamelen < 0) {
780 fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name);
783 do {
784 struct property *prop;
785 struct node *child;
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;
797 case FDT_BEGIN_NODE:
798 child = unflatten_tree(dtbuf,strbuf, node->fullpath,
799 flags);
800 add_child(node, child);
801 break;
803 case FDT_END_NODE:
804 break;
806 case FDT_END:
807 die("Premature FDT_END in device tree blob\n");
808 break;
810 case FDT_NOP:
811 if (!(flags & FTF_NOPS))
812 fprintf(stderr, "Warning: NOP tag found in flat tree"
813 " version <16\n");
815 /* Ignore */
816 break;
818 default:
819 die("Invalid opcode word %08x in device tree blob\n",
820 val);
822 } while (val != FDT_END_NODE);
824 return node;
828 struct boot_info *dt_from_blob(FILE *f)
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;
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");
855 magic = be32_to_cpu(magic);
856 if (magic != FDT_MAGIC)
857 die("Blob has incorrect magic number\n");
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");
869 totalsize = be32_to_cpu(totalsize);
870 if (totalsize < FDT_V1_SIZE)
871 die("DT blob size (%d) is too small\n", totalsize);
873 blob = xmalloc(totalsize);
875 fdt = (struct fdt_header *)blob;
876 fdt->magic = cpu_to_be32(magic);
877 fdt->totalsize = cpu_to_be32(totalsize);
879 sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
880 p = blob + sizeof(magic) + sizeof(totalsize);
882 while (sizeleft) {
883 if (feof(f))
884 die("EOF before reading %d bytes of DT blob\n",
885 totalsize);
887 rc = fread(p, 1, sizeleft, f);
888 if (ferror(f))
889 die("Error reading DT blob: %s\n",
890 strerror(errno));
892 sizeleft -= rc;
893 p += rc;
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);
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));
910 if (off_mem_rsvmap >= totalsize)
911 die("Mem Reserve structure offset exceeds total size\n");
913 if (off_dt >= totalsize)
914 die("DT structure offset exceeds total size\n");
916 if (off_str > totalsize)
917 die("String table offset exceeds total size\n");
919 if (version >= 2)
920 fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
921 be32_to_cpu(fdt->boot_cpuid_phys));
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");
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");
938 if (version < 16) {
939 flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
940 } else {
941 flags |= FTF_NOPS;
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);
952 reservelist = flat_read_mem_reserve(&memresvbuf);
954 val = flat_read_word(&dtbuf);
956 if (val != FDT_BEGIN_NODE)
957 die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
959 tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
961 val = flat_read_word(&dtbuf);
962 if (val != FDT_END)
963 die("Device tree blob doesn't end with FDT_END\n");
965 free(blob);
967 return build_boot_info(reservelist, tree);