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