1 /*- 2 * Copyright (c) 2013 David Chisnall 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 #include "fdt.hh" 34 35 #include <algorithm> 36 #include <inttypes.h> 37 #include <fcntl.h> 38 #include <libgen.h> 39 #include "dtb.hh" 40 41 namespace dtc 42 { 43 44 namespace fdt 45 { 46 47 uint32_t 48 property_value::get_as_uint32() 49 { 50 if (byte_data.size() != 4) 51 { 52 return 0; 53 } 54 uint32_t v = 0; 55 v &= byte_data[0] << 24; 56 v &= byte_data[1] << 16; 57 v &= byte_data[2] << 8; 58 v &= byte_data[3] << 0; 59 return v; 60 } 61 62 void 63 property_value::push_to_buffer(byte_buffer &buffer) 64 { 65 if (!byte_data.empty()) 66 { 67 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end()); 68 } 69 else 70 { 71 string_data.push_to_buffer(buffer, true); 72 // Trailing nul 73 buffer.push_back(0); 74 } 75 } 76 77 void 78 property_value::write_dts(FILE *file) 79 { 80 resolve_type(); 81 switch (type) 82 { 83 default: 84 assert(0 && "Invalid type"); 85 case STRING: 86 case STRING_LIST: 87 case CROSS_REFERENCE: 88 write_as_string(file); 89 break; 90 case PHANDLE: 91 write_as_cells(file); 92 break; 93 case BINARY: 94 if (byte_data.size() % 4 == 0) 95 { 96 write_as_cells(file); 97 break; 98 } 99 write_as_bytes(file); 100 break; 101 } 102 } 103 104 void 105 property_value::resolve_type() 106 { 107 if (type != UNKNOWN) 108 { 109 return; 110 } 111 if (byte_data.empty()) 112 { 113 type = STRING; 114 return; 115 } 116 if (byte_data.back() == 0) 117 { 118 bool is_all_printable = true; 119 int nuls = 0; 120 int bytes = 0; 121 for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i<e ; i++) 122 { 123 bytes++; 124 is_all_printable &= (*i == '\0') || isprint(*i); 125 if (*i == '\0') 126 { 127 nuls++; 128 } 129 if (!is_all_printable) 130 { 131 break; 132 } 133 } 134 if (is_all_printable && (bytes > nuls)) 135 { 136 type = STRING; 137 if (nuls > 0) 138 { 139 type = STRING_LIST; 140 } 141 return; 142 } 143 } 144 type = BINARY; 145 } 146 147 void 148 property_value::write_as_string(FILE *file) 149 { 150 putc('"', file); 151 if (byte_data.empty()) 152 { 153 string_data.print(file); 154 } 155 else 156 { 157 for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i!=e ; ++i) 158 { 159 // FIXME Escape tabs, newlines, and so on. 160 if (*i == '\0') 161 { 162 fputs("\", \"", file); 163 continue; 164 } 165 putc(*i, file); 166 } 167 } 168 putc('"', file); 169 } 170 171 void 172 property_value::write_as_cells(FILE *file) 173 { 174 putc('<', file); 175 assert((byte_data.size() % 4) == 0); 176 for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i) 177 { 178 uint32_t v = 0; 179 v = (v << 8) | *i; 180 ++i; 181 v = (v << 8) | *i; 182 ++i; 183 v = (v << 8) | *i; 184 ++i; 185 v = (v << 8) | *i; 186 fprintf(file, "0x%" PRIx32, v); 187 if (i+1 != e) 188 { 189 putc(' ', file); 190 } 191 } 192 putc('>', file); 193 } 194 195 void 196 property_value::write_as_bytes(FILE *file) 197 { 198 putc('[', file); 199 for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; i++) 200 { 201 fprintf(file, "%hhx", *i); 202 if (i+1 != e) 203 { 204 putc(' ', file); 205 } 206 } 207 putc(']', file); 208 } 209 210 void 211 property::parse_string(input_buffer &input) 212 { 213 property_value v; 214 assert(input[0] == '"'); 215 ++input; 216 const char *start = (const char*)input; 217 int length = 0; 218 while (char c = input[0]) 219 { 220 if (c == '"' && input[-1] != '\\') 221 { 222 input.consume('"'); 223 break; 224 } 225 ++input; 226 ++length; 227 } 228 v.string_data = string(start, length); 229 values.push_back(v); 230 } 231 232 void 233 property::parse_cells(input_buffer &input) 234 { 235 assert(input[0] == '<'); 236 ++input; 237 property_value v; 238 input.next_token(); 239 while (!input.consume('>')) 240 { 241 input.next_token(); 242 // If this is a phandle then we need to get the name of the 243 // referenced node 244 if (input.consume('&')) 245 { 246 input.next_token(); 247 // FIXME: We should support full paths here, but we 248 // don't. 249 string referenced = string::parse_node_name(input); 250 if (referenced.empty()) 251 { 252 input.parse_error("Expected node name"); 253 valid = false; 254 return; 255 } 256 input.next_token(); 257 // If we already have some bytes, make the phandle a 258 // separate component. 259 if (!v.byte_data.empty()) 260 { 261 values.push_back(v); 262 v = property_value(); 263 } 264 v.string_data = referenced; 265 v.type = property_value::PHANDLE; 266 values.push_back(v); 267 v = property_value(); 268 } 269 else 270 { 271 //FIXME: We should support labels in the middle 272 //of these, but we don't. 273 long long val; 274 if (!input.consume_integer(val)) 275 { 276 input.parse_error("Expected numbers in array of cells"); 277 valid = false; 278 return; 279 } 280 push_big_endian(v.byte_data, (uint32_t)val); 281 input.next_token(); 282 } 283 } 284 // Don't store an empty string value here. 285 if (v.byte_data.size() > 0) 286 { 287 values.push_back(v); 288 } 289 } 290 291 void 292 property::parse_bytes(input_buffer &input) 293 { 294 assert(input[0] == '['); 295 ++input; 296 property_value v; 297 input.next_token(); 298 while (!input.consume(']')) 299 { 300 { 301 //FIXME: We should support 302 //labels in the middle of 303 //these, but we don't. 304 uint8_t val; 305 if (!input.consume_hex_byte(val)) 306 { 307 input.parse_error("Expected hex bytes in array of bytes"); 308 valid = false; 309 return; 310 } 311 v.byte_data.push_back(val); 312 input.next_token(); 313 } 314 } 315 values.push_back(v); 316 } 317 318 void 319 property::parse_reference(input_buffer &input) 320 { 321 assert(input[0] == '&'); 322 ++input; 323 input.next_token(); 324 property_value v; 325 v.string_data = string::parse_node_name(input); 326 if (v.string_data.empty()) 327 { 328 input.parse_error("Expected node name"); 329 valid = false; 330 return; 331 } 332 v.type = property_value::CROSS_REFERENCE; 333 values.push_back(v); 334 } 335 336 property::property(input_buffer &structs, input_buffer &strings) 337 { 338 uint32_t name_offset; 339 uint32_t length; 340 valid = structs.consume_binary(length) && 341 structs.consume_binary(name_offset); 342 if (!valid) 343 { 344 fprintf(stderr, "Failed to read property\n"); 345 return; 346 } 347 // Find the name 348 input_buffer name_buffer = strings.buffer_from_offset(name_offset); 349 if (name_buffer.empty()) 350 { 351 fprintf(stderr, "Property name offset %" PRIu32 352 " is past the end of the strings table\n", 353 name_offset); 354 valid = false; 355 return; 356 } 357 key = string(name_buffer); 358 // Read the value 359 uint8_t byte; 360 property_value v; 361 for (uint32_t i=0 ; i<length ; i++) 362 { 363 if (!(valid = structs.consume_binary(byte))) 364 { 365 fprintf(stderr, "Failed to read property value\n"); 366 return; 367 } 368 v.byte_data.push_back(byte); 369 } 370 values.push_back(v); 371 } 372 373 property::property(input_buffer &input, string k, string l) : key(k), label(l), 374 valid(true) 375 { 376 do { 377 input.next_token(); 378 switch (input[0]) 379 { 380 default: 381 input.parse_error("Invalid property value."); 382 valid = false; 383 return; 384 case '"': 385 parse_string(input); 386 break; 387 case '<': 388 parse_cells(input); 389 break; 390 case '[': 391 parse_bytes(input); 392 break; 393 case '&': 394 parse_reference(input); 395 break; 396 case ';': 397 { 398 break; 399 } 400 } 401 input.next_token(); 402 } while (input.consume(',')); 403 if (!input.consume(';')) 404 { 405 input.parse_error("Expected ; at end of property"); 406 valid = false; 407 } 408 } 409 410 property* 411 property::parse_dtb(input_buffer &structs, input_buffer &strings) 412 { 413 property *p = new property(structs, strings); 414 if (!p->valid) 415 { 416 delete p; 417 p = 0; 418 } 419 return p; 420 } 421 422 property* 423 property::parse(input_buffer &input, string key, string label) 424 { 425 property *p = new property(input, key, label); 426 if (!p->valid) 427 { 428 delete p; 429 p = 0; 430 } 431 return p; 432 } 433 434 void 435 property::write(dtb::output_writer &writer, dtb::string_table &strings) 436 { 437 writer.write_token(dtb::FDT_PROP); 438 byte_buffer value_buffer; 439 for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 440 { 441 i->push_to_buffer(value_buffer); 442 } 443 writer.write_data((uint32_t)value_buffer.size()); 444 writer.write_comment(key); 445 writer.write_data(strings.add_string(key)); 446 writer.write_data(value_buffer); 447 } 448 449 void 450 property::write_dts(FILE *file, int indent) 451 { 452 for (int i=0 ; i<indent ; i++) 453 { 454 putc('\t', file); 455 } 456 if (label != string()) 457 { 458 label.print(file); 459 fputs(": ", file); 460 } 461 if (key != string()) 462 { 463 key.print(file); 464 } 465 if (!values.empty()) 466 { 467 fputs(" = ", file); 468 for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 469 { 470 i->write_dts(file); 471 if (i+1 != e) 472 { 473 putc(',', file); 474 putc(' ', file); 475 } 476 } 477 } 478 fputs(";\n", file); 479 } 480 481 string 482 node::parse_name(input_buffer &input, bool &is_property, const char *error) 483 { 484 if (!valid) 485 { 486 return string(); 487 } 488 input.next_token(); 489 if (is_property) 490 { 491 return string::parse_property_name(input); 492 } 493 string n = string::parse_node_or_property_name(input, is_property); 494 if (n.empty()) 495 { 496 if (n.empty()) 497 { 498 input.parse_error(error); 499 valid = false; 500 } 501 } 502 return n; 503 } 504 505 node::node(input_buffer &structs, input_buffer &strings) : valid(true) 506 { 507 const char *name_start = (const char*)structs; 508 int name_length = 0; 509 while (structs[0] != '\0' && structs[0] != '@') 510 { 511 name_length++; 512 ++structs; 513 } 514 name = string(name_start, name_length); 515 if (structs[0] == '@') 516 { 517 ++structs; 518 name_start = (const char*)structs; 519 name_length = 0; 520 while (structs[0] != '\0') 521 { 522 name_length++; 523 ++structs; 524 } 525 unit_address = string(name_start, name_length); 526 } 527 ++structs; 528 uint32_t token; 529 while (structs.consume_binary(token)) 530 { 531 switch (token) 532 { 533 default: 534 fprintf(stderr, "Unexpected token 0x%" PRIx32 535 " while parsing node.\n", token); 536 valid = false; 537 return; 538 // Child node, parse it. 539 case dtb::FDT_BEGIN_NODE: 540 { 541 node *child = node::parse_dtb(structs, strings); 542 if (child == 0) 543 { 544 valid = false; 545 return; 546 } 547 children.push_back(child); 548 break; 549 } 550 // End of this node, no errors. 551 case dtb::FDT_END_NODE: 552 return; 553 // Property, parse it. 554 case dtb::FDT_PROP: 555 { 556 property *prop = property::parse_dtb(structs, strings); 557 if (prop == 0) 558 { 559 valid = false; 560 return; 561 } 562 properties.push_back(prop); 563 break; 564 } 565 break; 566 // End of structs table. Should appear after 567 // the end of the last node. 568 case dtb::FDT_END: 569 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n"); 570 valid = false; 571 return; 572 // NOPs are padding. Ignore them. 573 case dtb::FDT_NOP: 574 break; 575 } 576 } 577 fprintf(stderr, "Failed to read token from structs table while parsing node.\n"); 578 valid = false; 579 return; 580 } 581 582 node::node(input_buffer &input, string n, string l, string a) : 583 label(l), name(n), unit_address(a), valid(true) 584 { 585 if (!input.consume('{')) 586 { 587 input.parse_error("Expected { to start new device tree node.\n"); 588 } 589 input.next_token(); 590 while (valid && !input.consume('}')) 591 { 592 // flag set if we find any characters that are only in 593 // the property name character set, not the node 594 bool is_property = false; 595 string child_name, child_label, child_address; 596 child_name = parse_name(input, is_property, 597 "Expected property or node name"); 598 if (input.consume(':')) 599 { 600 // Node labels can contain any characters? The 601 // spec doesn't say, so we guess so... 602 is_property = false; 603 child_label = child_name; 604 child_name = parse_name(input, is_property, "Expected property or node name"); 605 } 606 if (input.consume('@')) 607 { 608 child_address = parse_name(input, is_property, "Expected unit address"); 609 } 610 if (!valid) 611 { 612 return; 613 } 614 input.next_token(); 615 // If we're parsing a property, then we must actually do that. 616 if (input.consume('=')) 617 { 618 property *p= property::parse(input, child_name, 619 child_label); 620 if (p == 0) 621 { 622 valid = false; 623 } 624 else 625 { 626 properties.push_back(p); 627 } 628 } 629 else if (!is_property && input[0] == ('{')) 630 { 631 node *child = node::parse(input, child_name, 632 child_label, child_address); 633 if (child) 634 { 635 children.push_back(child); 636 } 637 else 638 { 639 valid = false; 640 } 641 } 642 else if (input.consume(';')) 643 { 644 properties.push_back(new property(child_name, child_label)); 645 } 646 else 647 { 648 input.parse_error("Error parsing property."); 649 valid = false; 650 } 651 input.next_token(); 652 } 653 input.consume(';'); 654 } 655 656 bool 657 node::cmp_properties(property *p1, property *p2) 658 { 659 return p1->get_key() < p2->get_key(); 660 } 661 662 bool 663 node::cmp_children(node *c1, node *c2) 664 { 665 if (c1->name == c2->name) 666 { 667 return c1->unit_address < c2->unit_address; 668 } 669 return c1->name < c2->name; 670 } 671 672 void 673 node::sort() 674 { 675 std::sort(property_begin(), property_end(), cmp_properties); 676 std::sort(child_begin(), child_end(), cmp_children); 677 for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 678 { 679 (*i)->sort(); 680 } 681 } 682 683 node* 684 node::parse(input_buffer &input, string name, string label, string address) 685 { 686 node *n = new node(input, name, label, address); 687 if (!n->valid) 688 { 689 delete n; 690 n = 0; 691 } 692 return n; 693 } 694 695 node* 696 node::parse_dtb(input_buffer &structs, input_buffer &strings) 697 { 698 node *n = new node(structs, strings); 699 if (!n->valid) 700 { 701 delete n; 702 n = 0; 703 } 704 return n; 705 } 706 707 node::~node() 708 { 709 while (!children.empty()) 710 { 711 delete children.back(); 712 children.pop_back(); 713 } 714 while (!properties.empty()) 715 { 716 delete properties.back(); 717 properties.pop_back(); 718 } 719 } 720 721 property* 722 node::get_property(string key) 723 { 724 for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 725 { 726 if ((*i)->get_key() == key) 727 { 728 return *i; 729 } 730 } 731 return 0; 732 } 733 734 void 735 node::merge_node(node *other) 736 { 737 if (!other->label.empty()) 738 { 739 label = other->label; 740 } 741 // Note: this is an O(n*m) operation. It might be sensible to 742 // optimise this if we find that there are nodes with very 743 // large numbers of properties, but for typical usage the 744 // entire vector will fit (easily) into cache, so iterating 745 // over it repeatedly isn't that expensive. 746 while (!other->properties.empty()) 747 { 748 property *p = other->properties.front(); 749 for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 750 { 751 if ((*i)->get_key() == p->get_key()) 752 { 753 delete *i; 754 properties.erase(i); 755 break; 756 } 757 } 758 add_property(p); 759 other->properties.erase(other->properties.begin()); 760 } 761 while (!other->children.empty()) 762 { 763 node *c = other->children.front(); 764 bool found = false; 765 for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 766 { 767 if ((*i)->name == c->name && (*i)->unit_address == c->unit_address) 768 { 769 (*i)->merge_node(c); 770 delete c; 771 found = true; 772 break; 773 } 774 } 775 if (!found) 776 { 777 children.push_back(c); 778 } 779 other->children.erase(other->children.begin()); 780 } 781 } 782 783 void 784 node::write(dtb::output_writer &writer, dtb::string_table &strings) 785 { 786 writer.write_token(dtb::FDT_BEGIN_NODE); 787 byte_buffer name_buffer; 788 name.push_to_buffer(name_buffer); 789 if (unit_address != string()) 790 { 791 name_buffer.push_back('@'); 792 unit_address.push_to_buffer(name_buffer); 793 } 794 writer.write_comment(name); 795 writer.write_data(name_buffer); 796 writer.write_data((uint8_t)0); 797 for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 798 { 799 (*i)->write(writer, strings); 800 } 801 for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 802 { 803 (*i)->write(writer, strings); 804 } 805 writer.write_token(dtb::FDT_END_NODE); 806 } 807 808 void 809 node::write_dts(FILE *file, int indent) 810 { 811 for (int i=0 ; i<indent ; i++) 812 { 813 putc('\t', file); 814 } 815 if (label != string()) 816 { 817 label.print(file); 818 fputs(": ", file); 819 } 820 if (name != string()) 821 { 822 name.print(file); 823 } 824 if (unit_address != string()) 825 { 826 putc('@', file); 827 unit_address.print(file); 828 } 829 fputs(" {\n\n", file); 830 for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 831 { 832 (*i)->write_dts(file, indent+1); 833 } 834 for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 835 { 836 (*i)->write_dts(file, indent+1); 837 } 838 for (int i=0 ; i<indent ; i++) 839 { 840 putc('\t', file); 841 } 842 fputs("};\n", file); 843 } 844 845 void 846 device_tree::collect_names_recursive(node* n, node_path &path) 847 { 848 string name = n->label; 849 path.push_back(std::make_pair(n->name, n->unit_address)); 850 if (name != string()) 851 { 852 if (node_names.find(name) == node_names.end()) 853 { 854 node_names.insert(std::make_pair(name, n)); 855 node_paths.insert(std::make_pair(name, path)); 856 } 857 else 858 { 859 node_names[name] = (node*)-1; 860 std::map<string, node_path>::iterator i = node_paths.find(name); 861 if (i != node_paths.end()) 862 { 863 node_paths.erase(name); 864 } 865 fprintf(stderr, "Label not unique: "); 866 name.dump(); 867 fprintf(stderr, ". References to this label will not be resolved."); 868 } 869 } 870 for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ; ++i) 871 { 872 collect_names_recursive(*i, path); 873 } 874 path.pop_back(); 875 // Now we collect the phandles and properties that reference 876 // other nodes. 877 for (node::property_iterator i=n->property_begin(), e=n->property_end() ; i!=e ; ++i) 878 { 879 for (property::value_iterator p=(*i)->begin(),pe=(*i)->end() ; p!=pe ; ++p) 880 { 881 if (p->is_phandle()) 882 { 883 phandles.push_back(&*p); 884 } 885 if (p->is_cross_reference()) 886 { 887 cross_references.push_back(&*p); 888 } 889 } 890 if ((*i)->get_key() == string("phandle") || 891 (*i)->get_key() == string("linux,phandle")) 892 { 893 if ((*i)->begin()->byte_data.size() != 4) 894 { 895 fprintf(stderr, "Invalid phandle value for node "); 896 n->name.dump(); 897 fprintf(stderr, ". Should be a 4-byte value.\n"); 898 valid = false; 899 } 900 else 901 { 902 uint32_t phandle = (*i)->begin()->get_as_uint32(); 903 used_phandles.insert(std::make_pair(phandle, n)); 904 } 905 } 906 } 907 } 908 909 void 910 device_tree::collect_names() 911 { 912 node_path p; 913 collect_names_recursive(root, p); 914 } 915 916 void 917 device_tree::resolve_cross_references() 918 { 919 for (std::vector<property_value*>::iterator i=cross_references.begin(), e=cross_references.end() ; i!=e ; ++i) 920 { 921 property_value* pv = *i; 922 node_path path = node_paths[pv->string_data]; 923 // Skip the first name in the path. It's always "", and implicitly / 924 for (node_path::iterator p=path.begin()+1, pe=path.end() ; p!=pe ; ++p) 925 { 926 pv->byte_data.push_back('/'); 927 p->first.push_to_buffer(pv->byte_data); 928 if (!(p->second.empty())) 929 { 930 pv->byte_data.push_back('@'); 931 p->second.push_to_buffer(pv->byte_data); 932 } 933 } 934 pv->byte_data.push_back(0); 935 } 936 uint32_t phandle = 1; 937 for (std::vector<property_value*>::iterator i=phandles.begin(), e=phandles.end() ; i!=e ; ++i) 938 { 939 string target_name = (*i)->string_data; 940 node *target = node_names[target_name]; 941 if (target == 0) 942 { 943 fprintf(stderr, "Failed to find node with label:"); 944 target_name.dump(); 945 fprintf(stderr, "\n"); 946 valid = 0; 947 return; 948 } 949 // If there is an existing phandle, use it 950 property *p = target->get_property("phandle"); 951 if (p == 0) 952 { 953 p = target->get_property("linux,phandle"); 954 } 955 if (p == 0) 956 { 957 // Otherwise insert a new phandle node 958 property_value v; 959 while (used_phandles.find(phandle) != used_phandles.end()) 960 { 961 // Note that we only don't need to 962 // store this phandle in the set, 963 // because we are monotonically 964 // increasing the value of phandle and 965 // so will only ever revisit this value 966 // if we have used 2^32 phandles, at 967 // which point our blob won't fit in 968 // any 32-bit system and we've done 969 // something badly wrong elsewhere 970 // already. 971 phandle++; 972 } 973 push_big_endian(v.byte_data, phandle++); 974 if (phandle_node_name == BOTH || phandle_node_name == LINUX) 975 { 976 p = new property(string("linux,phandle")); 977 p->add_value(v); 978 target->add_property(p); 979 } 980 if (phandle_node_name == BOTH || phandle_node_name == EPAPR) 981 { 982 p = new property(string("phandle")); 983 p->add_value(v); 984 target->add_property(p); 985 } 986 } 987 p->begin()->push_to_buffer((*i)->byte_data); 988 assert((*i)->byte_data.size() == 4); 989 } 990 } 991 992 void 993 device_tree::parse_roots(input_buffer &input, std::vector<node*> &roots) 994 { 995 input.next_token(); 996 while (valid && input.consume('/')) 997 { 998 input.next_token(); 999 node *n = node::parse(input, string("", 1)); 1000 if (n) 1001 { 1002 roots.push_back(n); 1003 } 1004 else 1005 { 1006 valid = false; 1007 } 1008 } 1009 } 1010 1011 input_buffer* 1012 device_tree::buffer_for_file(const char *path) 1013 { 1014 if (string(path) == string("-")) 1015 { 1016 input_buffer *b = new stream_input_buffer(); 1017 buffers.push_back(b); 1018 return b; 1019 } 1020 int source = open(path, O_RDONLY); 1021 if (source == -1) 1022 { 1023 fprintf(stderr, "Unable to open file %s\n", path); 1024 return 0; 1025 } 1026 input_buffer *b = new mmap_input_buffer(source); 1027 // Keep the buffer that owns the memory around for the lifetime 1028 // of this FDT. Ones simply referring to it may have shorter 1029 // lifetimes. 1030 buffers.push_back(b); 1031 close(source); 1032 return b; 1033 } 1034 1035 template<class writer> void 1036 device_tree::write(int fd) 1037 { 1038 dtb::string_table st; 1039 dtb::header head; 1040 writer head_writer; 1041 writer reservation_writer; 1042 writer struct_writer; 1043 writer strings_writer; 1044 1045 // Build the reservation table 1046 reservation_writer.write_comment(string("Memory reservations")); 1047 reservation_writer.write_label(string("dt_reserve_map")); 1048 for (std::vector<reservation>::iterator i=reservations.begin(), 1049 e=reservations.end() ; i!=e ; ++i) 1050 { 1051 reservation_writer.write_comment(string("Reservation start")); 1052 reservation_writer.write_data(i->first); 1053 reservation_writer.write_comment(string("Reservation length")); 1054 reservation_writer.write_data(i->first); 1055 } 1056 // Write n spare reserve map entries, plus the trailing 0. 1057 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++) 1058 { 1059 reservation_writer.write_data((uint64_t)0); 1060 reservation_writer.write_data((uint64_t)0); 1061 } 1062 1063 1064 struct_writer.write_comment(string("Device tree")); 1065 struct_writer.write_label(string("dt_struct_start")); 1066 root->write(struct_writer, st); 1067 struct_writer.write_token(dtb::FDT_END); 1068 struct_writer.write_label(string("dt_struct_end")); 1069 1070 st.write(strings_writer); 1071 // Find the strings size before we stick padding on the end. 1072 // Note: We should possibly use a new writer for the padding. 1073 head.size_dt_strings = strings_writer.size(); 1074 1075 // Stick the padding in the strings writer, but after the 1076 // marker indicating that it's the end. 1077 // Note: We probably should add a padding call to the writer so 1078 // that the asm back end can write padding directives instead 1079 // of a load of 0 bytes. 1080 for (uint32_t i=0 ; i<blob_padding ; i++) 1081 { 1082 strings_writer.write_data((uint8_t)0); 1083 } 1084 head.totalsize = sizeof(head) + strings_writer.size() + 1085 struct_writer.size() + reservation_writer.size(); 1086 while (head.totalsize < minimum_blob_size) 1087 { 1088 head.totalsize++; 1089 strings_writer.write_data((uint8_t)0); 1090 } 1091 head.off_dt_struct = sizeof(head) + reservation_writer.size();; 1092 head.off_dt_strings = head.off_dt_struct + struct_writer.size(); 1093 head.off_mem_rsvmap = sizeof(head); 1094 head.boot_cpuid_phys = boot_cpu; 1095 head.size_dt_struct = struct_writer.size(); 1096 head.write(head_writer); 1097 1098 head_writer.write_to_file(fd); 1099 reservation_writer.write_to_file(fd); 1100 struct_writer.write_to_file(fd); 1101 strings_writer.write_label(string("dt_blob_end")); 1102 strings_writer.write_to_file(fd); 1103 } 1104 1105 node* 1106 device_tree::referenced_node(property_value &v) 1107 { 1108 if (v.is_phandle()) 1109 { 1110 return node_names[v.string_data]; 1111 } 1112 if (v.is_binary()) 1113 { 1114 return used_phandles[v.get_as_uint32()]; 1115 } 1116 return 0; 1117 } 1118 1119 void 1120 device_tree::write_binary(int fd) 1121 { 1122 write<dtb::binary_writer>(fd); 1123 } 1124 1125 void 1126 device_tree::write_asm(int fd) 1127 { 1128 write<dtb::asm_writer>(fd); 1129 } 1130 1131 void 1132 device_tree::write_dts(int fd) 1133 { 1134 FILE *file = fdopen(fd, "w"); 1135 fputs("/dtc-v1/;\n\n", file); 1136 1137 if (!reservations.empty()) 1138 { 1139 const char msg[] = "/memreserve/"; 1140 fwrite(msg, sizeof(msg), 1, file); 1141 for (std::vector<reservation>::iterator i=reservations.begin(), 1142 e=reservations.end() ; i!=e ; ++i) 1143 { 1144 fprintf(stderr, " %" PRIx64 " %" PRIx64, i->first, i->second); 1145 } 1146 fputs(";\n\n", file); 1147 } 1148 putc('/', file); 1149 putc(' ', file); 1150 root->write_dts(file, 0); 1151 fclose(file); 1152 } 1153 1154 void 1155 device_tree::parse_dtb(const char *fn, FILE *depfile) 1156 { 1157 input_buffer *in = buffer_for_file(fn); 1158 if (in == 0) 1159 { 1160 valid = false; 1161 return; 1162 } 1163 input_buffer &input = *in; 1164 dtb::header h; 1165 valid = h.read_dtb(input); 1166 boot_cpu = h.boot_cpuid_phys; 1167 if (h.last_comp_version > 17) 1168 { 1169 fprintf(stderr, "Don't know how to read this version of the device tree blob"); 1170 valid = false; 1171 } 1172 if (!valid) 1173 { 1174 return; 1175 } 1176 input_buffer reservation_map = 1177 input.buffer_from_offset(h.off_mem_rsvmap, 0); 1178 uint64_t start, length; 1179 do 1180 { 1181 if (!(reservation_map.consume_binary(start) && 1182 reservation_map.consume_binary(length))) 1183 { 1184 fprintf(stderr, "Failed to read memory reservation table\n"); 1185 valid = false; 1186 return; 1187 } 1188 } while (!((start == 0) && (length == 0))); 1189 input_buffer struct_table = 1190 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct); 1191 input_buffer strings_table = 1192 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings); 1193 uint32_t token; 1194 if (!(struct_table.consume_binary(token) && 1195 (token == dtb::FDT_BEGIN_NODE))) 1196 { 1197 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n"); 1198 valid = false; 1199 return; 1200 } 1201 root = node::parse_dtb(struct_table, strings_table); 1202 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END))) 1203 { 1204 fprintf(stderr, "Expected FDT_END token after parsing root node.\n"); 1205 valid = false; 1206 return; 1207 } 1208 valid = (root != 0); 1209 } 1210 1211 void 1212 device_tree::parse_dts(const char *fn, FILE *depfile) 1213 { 1214 input_buffer *in = buffer_for_file(fn); 1215 if (in == 0) 1216 { 1217 valid = false; 1218 return; 1219 } 1220 std::vector<node*> roots; 1221 input_buffer &input = *in; 1222 input.next_token(); 1223 bool read_header = false; 1224 // Read the header 1225 if (input.consume("/dts-v1/;")) 1226 { 1227 read_header = true; 1228 } 1229 input.next_token(); 1230 while(input.consume("/include/")) 1231 { 1232 input.next_token(); 1233 if (!input.consume('"')) 1234 { 1235 input.parse_error("Expected quoted filename"); 1236 valid = false; 1237 return; 1238 } 1239 int length = 0; 1240 while (input[length] != '"') length++; 1241 1242 const char *file = (const char*)input; 1243 const char *dir = dirname(fn); 1244 int dir_length = strlen(dir); 1245 char *include_file = (char*)malloc(strlen(dir) + length + 2); 1246 memcpy(include_file, dir, dir_length); 1247 include_file[dir_length] = '/'; 1248 memcpy(include_file+dir_length+1, file, length); 1249 include_file[dir_length+length+1] = 0; 1250 input_buffer *include_buffer = buffer_for_file(include_file); 1251 1252 if (include_buffer == 0) 1253 { 1254 for (std::vector<const char*>::iterator i=include_paths.begin(), e=include_paths.end() ; e!=i ; ++i) 1255 { 1256 free(include_file); 1257 dir = *i; 1258 dir_length = strlen(dir); 1259 include_file = (char*)malloc(strlen(dir) + 1260 length + 2); 1261 memcpy(include_file, dir, dir_length); 1262 include_file[dir_length] = '/'; 1263 memcpy(include_file+dir_length+1, file, length); 1264 include_file[dir_length+length+1] = 0; 1265 include_buffer = buffer_for_file(include_file); 1266 if (include_buffer != 0) 1267 { 1268 break; 1269 } 1270 } 1271 } 1272 if (depfile != 0) 1273 { 1274 putc(' ', depfile); 1275 fputs(include_file, depfile); 1276 } 1277 if (include_buffer == 0) 1278 { 1279 valid = false; 1280 return; 1281 } 1282 input_buffer &include = *include_buffer; 1283 input.consume(include_file+dir_length+1); 1284 input.consume('"'); 1285 free((void*)include_file); 1286 1287 if (!read_header) 1288 { 1289 include.next_token(); 1290 read_header = include.consume("/dts-v1/;"); 1291 } 1292 parse_roots(include, roots); 1293 } 1294 input.next_token(); 1295 if (!read_header) 1296 { 1297 input.parse_error("Expected /dts-v1/; version string"); 1298 } 1299 // Read any memory reservations 1300 while(input.consume("/memreserve/")) 1301 { 1302 long long start, len; 1303 input.next_token(); 1304 // Read the start and length. 1305 if (!(input.consume_integer(start) && 1306 (input.next_token(), 1307 input.consume_integer(len)))) 1308 { 1309 input.parse_error("Expected /dts-v1/; version string"); 1310 } 1311 input.next_token(); 1312 input.consume(';'); 1313 reservations.push_back(reservation(start, len)); 1314 } 1315 parse_roots(input, roots); 1316 switch (roots.size()) 1317 { 1318 case 0: 1319 valid = false; 1320 input.parse_error("Failed to find root node /."); 1321 return; 1322 case 1: 1323 root = roots[0]; 1324 break; 1325 default: 1326 { 1327 root = roots[0]; 1328 for (std::vector<node*>::iterator i=roots.begin()+1, 1329 e=roots.end() ; i!=e ; ++i) 1330 { 1331 root->merge_node(*i); 1332 delete *i; 1333 } 1334 roots.resize(1); 1335 } 1336 } 1337 collect_names(); 1338 resolve_cross_references(); 1339 } 1340 1341 device_tree::~device_tree() 1342 { 1343 if (root != 0) 1344 { 1345 delete root; 1346 } 1347 while (!buffers.empty()) 1348 { 1349 delete buffers.back(); 1350 buffers.pop_back(); 1351 } 1352 } 1353 1354 } // namespace fdt 1355 1356 } // namespace dtc 1357 1358