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