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