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 #include "dtb.hh" 37 38 #include <algorithm> 39 #include <sstream> 40 41 #include <ctype.h> 42 #include <fcntl.h> 43 #include <inttypes.h> 44 #include <libgen.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <errno.h> 51 52 using std::string; 53 54 namespace dtc 55 { 56 57 namespace fdt 58 { 59 60 uint32_t 61 property_value::get_as_uint32() 62 { 63 if (byte_data.size() != 4) 64 { 65 return 0; 66 } 67 uint32_t v = 0; 68 v &= byte_data[0] << 24; 69 v &= byte_data[1] << 16; 70 v &= byte_data[2] << 8; 71 v &= byte_data[3] << 0; 72 return v; 73 } 74 75 void 76 property_value::push_to_buffer(byte_buffer &buffer) 77 { 78 if (!byte_data.empty()) 79 { 80 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end()); 81 } 82 else 83 { 84 push_string(buffer, string_data, true); 85 // Trailing nul 86 buffer.push_back(0); 87 } 88 } 89 90 void 91 property_value::write_dts(FILE *file) 92 { 93 resolve_type(); 94 switch (type) 95 { 96 default: 97 assert(0 && "Invalid type"); 98 case STRING: 99 case STRING_LIST: 100 case CROSS_REFERENCE: 101 write_as_string(file); 102 break; 103 case PHANDLE: 104 write_as_cells(file); 105 break; 106 case BINARY: 107 if (byte_data.size() % 4 == 0) 108 { 109 write_as_cells(file); 110 break; 111 } 112 write_as_bytes(file); 113 break; 114 } 115 } 116 117 void 118 property_value::resolve_type() 119 { 120 if (type != UNKNOWN) 121 { 122 return; 123 } 124 if (byte_data.empty()) 125 { 126 type = STRING; 127 return; 128 } 129 if (byte_data.back() == 0) 130 { 131 bool is_all_printable = true; 132 int nuls = 0; 133 int bytes = 0; 134 bool lastWasNull = false; 135 for (auto i : byte_data) 136 { 137 bytes++; 138 is_all_printable &= (i == '\0') || isprint(i); 139 if (i == '\0') 140 { 141 // If there are two nulls in a row, then we're probably binary. 142 if (lastWasNull) 143 { 144 type = BINARY; 145 return; 146 } 147 nuls++; 148 lastWasNull = true; 149 } 150 else 151 { 152 lastWasNull = false; 153 } 154 if (!is_all_printable) 155 { 156 break; 157 } 158 } 159 if ((is_all_printable && (bytes > nuls)) || bytes == 0) 160 { 161 type = STRING; 162 if (nuls > 1) 163 { 164 type = STRING_LIST; 165 } 166 return; 167 } 168 } 169 type = BINARY; 170 } 171 172 void 173 property_value::write_as_string(FILE *file) 174 { 175 putc('"', file); 176 if (byte_data.empty()) 177 { 178 fputs(string_data.c_str(), file); 179 } 180 else 181 { 182 bool hasNull = (byte_data.back() == '\0'); 183 // Remove trailing null bytes from the string before printing as dts. 184 if (hasNull) 185 { 186 byte_data.pop_back(); 187 } 188 for (auto i : byte_data) 189 { 190 // FIXME Escape tabs, newlines, and so on. 191 if (i == '\0') 192 { 193 fputs("\", \"", file); 194 continue; 195 } 196 putc(i, file); 197 } 198 if (hasNull) 199 { 200 byte_data.push_back('\0'); 201 } 202 } 203 putc('"', file); 204 } 205 206 void 207 property_value::write_as_cells(FILE *file) 208 { 209 putc('<', file); 210 assert((byte_data.size() % 4) == 0); 211 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i) 212 { 213 uint32_t v = 0; 214 v = (v << 8) | *i; 215 ++i; 216 v = (v << 8) | *i; 217 ++i; 218 v = (v << 8) | *i; 219 ++i; 220 v = (v << 8) | *i; 221 fprintf(file, "0x%" PRIx32, v); 222 if (i+1 != e) 223 { 224 putc(' ', file); 225 } 226 } 227 putc('>', file); 228 } 229 230 void 231 property_value::write_as_bytes(FILE *file) 232 { 233 putc('[', file); 234 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++) 235 { 236 fprintf(file, "%02hhx", *i); 237 if (i+1 != e) 238 { 239 putc(' ', file); 240 } 241 } 242 putc(']', file); 243 } 244 245 void 246 property::parse_string(text_input_buffer &input) 247 { 248 property_value v; 249 assert(*input == '"'); 250 ++input; 251 std::vector<char> bytes; 252 bool isEscaped = false; 253 while (char c = *input) 254 { 255 if (c == '"' && !isEscaped) 256 { 257 input.consume('"'); 258 break; 259 } 260 isEscaped = (c == '\\'); 261 bytes.push_back(c); 262 ++input; 263 } 264 v.string_data = string(bytes.begin(), bytes.end()); 265 values.push_back(v); 266 } 267 268 void 269 property::parse_cells(text_input_buffer &input, int cell_size) 270 { 271 assert(*input == '<'); 272 ++input; 273 property_value v; 274 input.next_token(); 275 while (!input.consume('>')) 276 { 277 input.next_token(); 278 // If this is a phandle then we need to get the name of the 279 // referenced node 280 if (input.consume('&')) 281 { 282 if (cell_size != 32) 283 { 284 input.parse_error("reference only permitted in 32-bit arrays"); 285 valid = false; 286 return; 287 } 288 input.next_token(); 289 bool isPath = false; 290 string referenced; 291 if (!input.consume('{')) 292 { 293 referenced = input.parse_node_name(); 294 } 295 else 296 { 297 referenced = input.parse_to('}'); 298 input.consume('}'); 299 isPath = true; 300 } 301 if (referenced.empty()) 302 { 303 input.parse_error("Expected node name"); 304 valid = false; 305 return; 306 } 307 input.next_token(); 308 // If we already have some bytes, make the phandle a 309 // separate component. 310 if (!v.byte_data.empty()) 311 { 312 values.push_back(v); 313 v = property_value(); 314 } 315 v.string_data = referenced; 316 v.type = property_value::PHANDLE; 317 values.push_back(v); 318 v = property_value(); 319 } 320 else 321 { 322 //FIXME: We should support labels in the middle 323 //of these, but we don't. 324 unsigned long long val; 325 if (!input.consume_integer_expression(val)) 326 { 327 input.parse_error("Expected numbers in array of cells"); 328 valid = false; 329 return; 330 } 331 switch (cell_size) 332 { 333 case 8: 334 v.byte_data.push_back(val); 335 break; 336 case 16: 337 push_big_endian(v.byte_data, (uint16_t)val); 338 break; 339 case 32: 340 push_big_endian(v.byte_data, (uint32_t)val); 341 break; 342 case 64: 343 push_big_endian(v.byte_data, (uint64_t)val); 344 break; 345 default: 346 assert(0 && "Invalid cell size!"); 347 } 348 input.next_token(); 349 } 350 } 351 // Don't store an empty string value here. 352 if (v.byte_data.size() > 0) 353 { 354 values.push_back(v); 355 } 356 } 357 358 void 359 property::parse_bytes(text_input_buffer &input) 360 { 361 assert(*input == '['); 362 ++input; 363 property_value v; 364 input.next_token(); 365 while (!input.consume(']')) 366 { 367 { 368 //FIXME: We should support 369 //labels in the middle of 370 //these, but we don't. 371 uint8_t val; 372 if (!input.consume_hex_byte(val)) 373 { 374 input.parse_error("Expected hex bytes in array of bytes"); 375 valid = false; 376 return; 377 } 378 v.byte_data.push_back(val); 379 input.next_token(); 380 } 381 } 382 values.push_back(v); 383 } 384 385 void 386 property::parse_reference(text_input_buffer &input) 387 { 388 assert(*input == '&'); 389 ++input; 390 input.next_token(); 391 property_value v; 392 v.string_data = input.parse_node_name(); 393 if (v.string_data.empty()) 394 { 395 input.parse_error("Expected node name"); 396 valid = false; 397 return; 398 } 399 v.type = property_value::CROSS_REFERENCE; 400 values.push_back(v); 401 } 402 403 property::property(input_buffer &structs, input_buffer &strings) 404 { 405 uint32_t name_offset; 406 uint32_t length; 407 valid = structs.consume_binary(length) && 408 structs.consume_binary(name_offset); 409 if (!valid) 410 { 411 fprintf(stderr, "Failed to read property\n"); 412 return; 413 } 414 // Find the name 415 input_buffer name_buffer = strings.buffer_from_offset(name_offset); 416 if (name_buffer.finished()) 417 { 418 fprintf(stderr, "Property name offset %" PRIu32 419 " is past the end of the strings table\n", 420 name_offset); 421 valid = false; 422 return; 423 } 424 key = name_buffer.parse_to(0); 425 426 // If we're empty, do not push anything as value. 427 if (!length) 428 return; 429 430 // Read the value 431 uint8_t byte; 432 property_value v; 433 for (uint32_t i=0 ; i<length ; i++) 434 { 435 if (!(valid = structs.consume_binary(byte))) 436 { 437 fprintf(stderr, "Failed to read property value\n"); 438 return; 439 } 440 v.byte_data.push_back(byte); 441 } 442 values.push_back(v); 443 } 444 445 void property::parse_define(text_input_buffer &input, define_map *defines) 446 { 447 input.consume('$'); 448 if (!defines) 449 { 450 input.parse_error("No predefined properties to match name\n"); 451 valid = false; 452 return; 453 } 454 string name = input.parse_property_name(); 455 define_map::iterator found; 456 if ((name == string()) || 457 ((found = defines->find(name)) == defines->end())) 458 { 459 input.parse_error("Undefined property name\n"); 460 valid = false; 461 return; 462 } 463 values.push_back((*found).second->values[0]); 464 } 465 466 property::property(text_input_buffer &input, 467 string &&k, 468 string_set &&l, 469 bool semicolonTerminated, 470 define_map *defines) : key(k), labels(l), valid(true) 471 { 472 do { 473 input.next_token(); 474 switch (*input) 475 { 476 case '$': 477 { 478 parse_define(input, defines); 479 if (valid) 480 { 481 break; 482 } 483 } 484 default: 485 input.parse_error("Invalid property value."); 486 valid = false; 487 return; 488 case '/': 489 { 490 unsigned long long bits = 0; 491 valid = input.consume("/bits/"); 492 input.next_token(); 493 valid &= input.consume_integer(bits); 494 if ((bits != 8) && 495 (bits != 16) && 496 (bits != 32) && 497 (bits != 64)) { 498 input.parse_error("Invalid size for elements"); 499 valid = false; 500 } 501 if (!valid) return; 502 input.next_token(); 503 if (*input != '<') 504 { 505 input.parse_error("/bits/ directive is only valid on arrays"); 506 valid = false; 507 return; 508 } 509 parse_cells(input, bits); 510 break; 511 } 512 case '"': 513 parse_string(input); 514 break; 515 case '<': 516 parse_cells(input, 32); 517 break; 518 case '[': 519 parse_bytes(input); 520 break; 521 case '&': 522 parse_reference(input); 523 break; 524 case ';': 525 { 526 break; 527 } 528 } 529 input.next_token(); 530 } while (input.consume(',')); 531 if (semicolonTerminated && !input.consume(';')) 532 { 533 input.parse_error("Expected ; at end of property"); 534 valid = false; 535 } 536 } 537 538 property_ptr 539 property::parse_dtb(input_buffer &structs, input_buffer &strings) 540 { 541 property_ptr p(new property(structs, strings)); 542 if (!p->valid) 543 { 544 p = nullptr; 545 } 546 return p; 547 } 548 549 property_ptr 550 property::parse(text_input_buffer &input, string &&key, string_set &&label, 551 bool semicolonTerminated, define_map *defines) 552 { 553 property_ptr p(new property(input, 554 std::move(key), 555 std::move(label), 556 semicolonTerminated, 557 defines)); 558 if (!p->valid) 559 { 560 p = nullptr; 561 } 562 return p; 563 } 564 565 void 566 property::write(dtb::output_writer &writer, dtb::string_table &strings) 567 { 568 writer.write_token(dtb::FDT_PROP); 569 byte_buffer value_buffer; 570 for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 571 { 572 i->push_to_buffer(value_buffer); 573 } 574 writer.write_data((uint32_t)value_buffer.size()); 575 writer.write_comment(key); 576 writer.write_data(strings.add_string(key)); 577 writer.write_data(value_buffer); 578 } 579 580 bool 581 property_value::try_to_merge(property_value &other) 582 { 583 resolve_type(); 584 switch (type) 585 { 586 case UNKNOWN: 587 __builtin_unreachable(); 588 assert(0); 589 return false; 590 case EMPTY: 591 *this = other; 592 case STRING: 593 case STRING_LIST: 594 case CROSS_REFERENCE: 595 return false; 596 case PHANDLE: 597 case BINARY: 598 if (other.type == PHANDLE || other.type == BINARY) 599 { 600 type = BINARY; 601 byte_data.insert(byte_data.end(), other.byte_data.begin(), 602 other.byte_data.end()); 603 return true; 604 } 605 } 606 return false; 607 } 608 609 void 610 property::write_dts(FILE *file, int indent) 611 { 612 for (int i=0 ; i<indent ; i++) 613 { 614 putc('\t', file); 615 } 616 #ifdef PRINT_LABELS 617 for (auto &l : labels) 618 { 619 fputs(l.c_str(), file); 620 fputs(": ", file); 621 } 622 #endif 623 if (key != string()) 624 { 625 fputs(key.c_str(), file); 626 } 627 if (!values.empty()) 628 { 629 std::vector<property_value> *vals = &values; 630 std::vector<property_value> v; 631 // If we've got multiple values then try to merge them all together. 632 if (values.size() > 1) 633 { 634 vals = &v; 635 v.push_back(values.front()); 636 for (auto i=(++begin()), e=end() ; i!=e ; ++i) 637 { 638 if (!v.back().try_to_merge(*i)) 639 { 640 v.push_back(*i); 641 } 642 } 643 } 644 fputs(" = ", file); 645 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i) 646 { 647 i->write_dts(file); 648 if (i+1 != e) 649 { 650 putc(',', file); 651 putc(' ', file); 652 } 653 } 654 } 655 fputs(";\n", file); 656 } 657 658 string 659 node::parse_name(text_input_buffer &input, bool &is_property, const char *error) 660 { 661 if (!valid) 662 { 663 return string(); 664 } 665 input.next_token(); 666 if (is_property) 667 { 668 return input.parse_property_name(); 669 } 670 string n = input.parse_node_or_property_name(is_property); 671 if (n.empty()) 672 { 673 if (n.empty()) 674 { 675 input.parse_error(error); 676 valid = false; 677 } 678 } 679 return n; 680 } 681 682 void 683 node::visit(std::function<void(node&)> fn) 684 { 685 fn(*this); 686 for (auto &&c : children) 687 { 688 c->visit(fn); 689 } 690 } 691 692 node::node(input_buffer &structs, input_buffer &strings) : valid(true) 693 { 694 std::vector<char> bytes; 695 while (structs[0] != '\0' && structs[0] != '@') 696 { 697 bytes.push_back(structs[0]); 698 ++structs; 699 } 700 name = string(bytes.begin(), bytes.end()); 701 bytes.clear(); 702 if (structs[0] == '@') 703 { 704 ++structs; 705 while (structs[0] != '\0') 706 { 707 bytes.push_back(structs[0]); 708 ++structs; 709 } 710 unit_address = string(bytes.begin(), bytes.end()); 711 } 712 ++structs; 713 uint32_t token; 714 while (structs.consume_binary(token)) 715 { 716 switch (token) 717 { 718 default: 719 fprintf(stderr, "Unexpected token 0x%" PRIx32 720 " while parsing node.\n", token); 721 valid = false; 722 return; 723 // Child node, parse it. 724 case dtb::FDT_BEGIN_NODE: 725 { 726 node_ptr child = node::parse_dtb(structs, strings); 727 if (child == 0) 728 { 729 valid = false; 730 return; 731 } 732 children.push_back(std::move(child)); 733 break; 734 } 735 // End of this node, no errors. 736 case dtb::FDT_END_NODE: 737 return; 738 // Property, parse it. 739 case dtb::FDT_PROP: 740 { 741 property_ptr prop = property::parse_dtb(structs, strings); 742 if (prop == 0) 743 { 744 valid = false; 745 return; 746 } 747 props.push_back(prop); 748 break; 749 } 750 break; 751 // End of structs table. Should appear after 752 // the end of the last node. 753 case dtb::FDT_END: 754 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n"); 755 valid = false; 756 return; 757 // NOPs are padding. Ignore them. 758 case dtb::FDT_NOP: 759 break; 760 } 761 } 762 fprintf(stderr, "Failed to read token from structs table while parsing node.\n"); 763 valid = false; 764 return; 765 } 766 767 node::node(text_input_buffer &input, 768 string &&n, 769 std::unordered_set<string> &&l, 770 string &&a, 771 define_map *defines) 772 : labels(l), name(n), unit_address(a), valid(true) 773 { 774 if (!input.consume('{')) 775 { 776 input.parse_error("Expected { to start new device tree node.\n"); 777 } 778 input.next_token(); 779 while (valid && !input.consume('}')) 780 { 781 // flag set if we find any characters that are only in 782 // the property name character set, not the node 783 bool is_property = false; 784 string child_name, child_address; 785 std::unordered_set<string> child_labels; 786 auto parse_delete = [&](const char *expected, bool at) 787 { 788 if (child_name == string()) 789 { 790 input.parse_error(expected); 791 valid = false; 792 return; 793 } 794 input.next_token(); 795 if (at && input.consume('@')) 796 { 797 child_name += '@'; 798 child_name += parse_name(input, is_property, "Expected unit address"); 799 } 800 if (!input.consume(';')) 801 { 802 input.parse_error("Expected semicolon"); 803 valid = false; 804 return; 805 } 806 input.next_token(); 807 }; 808 if (input.consume("/delete-node/")) 809 { 810 input.next_token(); 811 child_name = input.parse_node_name(); 812 parse_delete("Expected node name", true); 813 if (valid) 814 { 815 deleted_children.insert(child_name); 816 } 817 continue; 818 } 819 if (input.consume("/delete-property/")) 820 { 821 input.next_token(); 822 child_name = input.parse_property_name(); 823 parse_delete("Expected property name", false); 824 if (valid) 825 { 826 deleted_props.insert(child_name); 827 } 828 continue; 829 } 830 child_name = parse_name(input, is_property, 831 "Expected property or node name"); 832 while (input.consume(':')) 833 { 834 // Node labels can contain any characters? The 835 // spec doesn't say, so we guess so... 836 is_property = false; 837 child_labels.insert(std::move(child_name)); 838 child_name = parse_name(input, is_property, "Expected property or node name"); 839 } 840 if (input.consume('@')) 841 { 842 child_address = parse_name(input, is_property, "Expected unit address"); 843 } 844 if (!valid) 845 { 846 return; 847 } 848 input.next_token(); 849 // If we're parsing a property, then we must actually do that. 850 if (input.consume('=')) 851 { 852 property_ptr p = property::parse(input, std::move(child_name), 853 std::move(child_labels), true, defines); 854 if (p == 0) 855 { 856 valid = false; 857 } 858 else 859 { 860 props.push_back(p); 861 } 862 } 863 else if (!is_property && *input == ('{')) 864 { 865 node_ptr child = node::parse(input, std::move(child_name), 866 std::move(child_labels), std::move(child_address), defines); 867 if (child) 868 { 869 children.push_back(std::move(child)); 870 } 871 else 872 { 873 valid = false; 874 } 875 } 876 else if (input.consume(';')) 877 { 878 props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels)))); 879 } 880 else 881 { 882 input.parse_error("Error parsing property. Expected property value"); 883 valid = false; 884 } 885 input.next_token(); 886 } 887 input.next_token(); 888 input.consume(';'); 889 } 890 891 bool 892 node::cmp_properties(property_ptr &p1, property_ptr &p2) 893 { 894 return p1->get_key() < p2->get_key(); 895 } 896 897 bool 898 node::cmp_children(node_ptr &c1, node_ptr &c2) 899 { 900 if (c1->name == c2->name) 901 { 902 return c1->unit_address < c2->unit_address; 903 } 904 return c1->name < c2->name; 905 } 906 907 void 908 node::sort() 909 { 910 std::sort(property_begin(), property_end(), cmp_properties); 911 std::sort(child_begin(), child_end(), cmp_children); 912 for (auto &c : child_nodes()) 913 { 914 c->sort(); 915 } 916 } 917 918 node_ptr 919 node::parse(text_input_buffer &input, 920 string &&name, 921 string_set &&label, 922 string &&address, 923 define_map *defines) 924 { 925 node_ptr n(new node(input, 926 std::move(name), 927 std::move(label), 928 std::move(address), 929 defines)); 930 if (!n->valid) 931 { 932 n = 0; 933 } 934 return n; 935 } 936 937 node_ptr 938 node::parse_dtb(input_buffer &structs, input_buffer &strings) 939 { 940 node_ptr n(new node(structs, strings)); 941 if (!n->valid) 942 { 943 n = 0; 944 } 945 return n; 946 } 947 948 property_ptr 949 node::get_property(const string &key) 950 { 951 for (auto &i : props) 952 { 953 if (i->get_key() == key) 954 { 955 return i; 956 } 957 } 958 return 0; 959 } 960 961 void 962 node::merge_node(node_ptr other) 963 { 964 for (auto &l : other->labels) 965 { 966 labels.insert(l); 967 } 968 // Note: this is an O(n*m) operation. It might be sensible to 969 // optimise this if we find that there are nodes with very 970 // large numbers of properties, but for typical usage the 971 // entire vector will fit (easily) into cache, so iterating 972 // over it repeatedly isn't that expensive. 973 for (auto &p : other->properties()) 974 { 975 bool found = false; 976 for (auto &mp : properties()) 977 { 978 if (mp->get_key() == p->get_key()) 979 { 980 mp = p; 981 found = true; 982 break; 983 } 984 } 985 if (!found) 986 { 987 add_property(p); 988 } 989 } 990 for (auto &c : other->children) 991 { 992 bool found = false; 993 for (auto &i : children) 994 { 995 if (i->name == c->name && i->unit_address == c->unit_address) 996 { 997 i->merge_node(std::move(c)); 998 found = true; 999 break; 1000 } 1001 } 1002 if (!found) 1003 { 1004 children.push_back(std::move(c)); 1005 } 1006 } 1007 children.erase(std::remove_if(children.begin(), children.end(), 1008 [&](const node_ptr &p) { 1009 string full_name = p->name; 1010 if (p->unit_address != string()) 1011 { 1012 full_name += '@'; 1013 full_name += p->unit_address; 1014 } 1015 if (other->deleted_children.count(full_name) > 0) 1016 { 1017 other->deleted_children.erase(full_name); 1018 return true; 1019 } 1020 return false; 1021 }), children.end()); 1022 props.erase(std::remove_if(props.begin(), props.end(), 1023 [&](const property_ptr &p) { 1024 if (other->deleted_props.count(p->get_key()) > 0) 1025 { 1026 other->deleted_props.erase(p->get_key()); 1027 return true; 1028 } 1029 return false; 1030 }), props.end()); 1031 } 1032 1033 void 1034 node::write(dtb::output_writer &writer, dtb::string_table &strings) 1035 { 1036 writer.write_token(dtb::FDT_BEGIN_NODE); 1037 byte_buffer name_buffer; 1038 push_string(name_buffer, name); 1039 if (unit_address != string()) 1040 { 1041 name_buffer.push_back('@'); 1042 push_string(name_buffer, unit_address); 1043 } 1044 writer.write_comment(name); 1045 writer.write_data(name_buffer); 1046 writer.write_data((uint8_t)0); 1047 for (auto p : properties()) 1048 { 1049 p->write(writer, strings); 1050 } 1051 for (auto &c : child_nodes()) 1052 { 1053 c->write(writer, strings); 1054 } 1055 writer.write_token(dtb::FDT_END_NODE); 1056 } 1057 1058 void 1059 node::write_dts(FILE *file, int indent) 1060 { 1061 for (int i=0 ; i<indent ; i++) 1062 { 1063 putc('\t', file); 1064 } 1065 #ifdef PRINT_LABELS 1066 for (auto &label : labels) 1067 { 1068 fprintf(file, "%s: ", label.c_str()); 1069 } 1070 #endif 1071 if (name != string()) 1072 { 1073 fputs(name.c_str(), file); 1074 } 1075 if (unit_address != string()) 1076 { 1077 putc('@', file); 1078 fputs(unit_address.c_str(), file); 1079 } 1080 fputs(" {\n\n", file); 1081 for (auto p : properties()) 1082 { 1083 p->write_dts(file, indent+1); 1084 } 1085 for (auto &c : child_nodes()) 1086 { 1087 c->write_dts(file, indent+1); 1088 } 1089 for (int i=0 ; i<indent ; i++) 1090 { 1091 putc('\t', file); 1092 } 1093 fputs("};\n", file); 1094 } 1095 1096 void 1097 device_tree::collect_names_recursive(node_ptr &n, node_path &path) 1098 { 1099 path.push_back(std::make_pair(n->name, n->unit_address)); 1100 for (const string &name : n->labels) 1101 { 1102 if (name != string()) 1103 { 1104 auto iter = node_names.find(name); 1105 if (iter == node_names.end()) 1106 { 1107 node_names.insert(std::make_pair(name, n.get())); 1108 node_paths.insert(std::make_pair(name, path)); 1109 } 1110 else 1111 { 1112 node_names.erase(iter); 1113 auto i = node_paths.find(name); 1114 if (i != node_paths.end()) 1115 { 1116 node_paths.erase(name); 1117 } 1118 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str()); 1119 } 1120 } 1121 } 1122 for (auto &c : n->child_nodes()) 1123 { 1124 collect_names_recursive(c, path); 1125 } 1126 path.pop_back(); 1127 // Now we collect the phandles and properties that reference 1128 // other nodes. 1129 for (auto &p : n->properties()) 1130 { 1131 for (auto &v : *p) 1132 { 1133 if (v.is_phandle()) 1134 { 1135 phandles.push_back(&v); 1136 } 1137 if (v.is_cross_reference()) 1138 { 1139 cross_references.push_back(&v); 1140 } 1141 } 1142 if ((p->get_key() == "phandle") || 1143 (p->get_key() == "linux,phandle")) 1144 { 1145 if (p->begin()->byte_data.size() != 4) 1146 { 1147 fprintf(stderr, "Invalid phandle value for node %s. Should be a 4-byte value.\n", n->name.c_str()); 1148 valid = false; 1149 } 1150 else 1151 { 1152 uint32_t phandle = p->begin()->get_as_uint32(); 1153 used_phandles.insert(std::make_pair(phandle, n.get())); 1154 } 1155 } 1156 } 1157 } 1158 1159 void 1160 device_tree::collect_names() 1161 { 1162 node_path p; 1163 node_names.clear(); 1164 node_paths.clear(); 1165 cross_references.clear(); 1166 phandles.clear(); 1167 collect_names_recursive(root, p); 1168 } 1169 1170 void 1171 device_tree::resolve_cross_references() 1172 { 1173 for (auto *pv : cross_references) 1174 { 1175 node_path path = node_paths[pv->string_data]; 1176 auto p = path.begin(); 1177 auto pe = path.end(); 1178 if (p != pe) 1179 { 1180 // Skip the first name in the path. It's always "", and implicitly / 1181 for (++p ; p!=pe ; ++p) 1182 { 1183 pv->byte_data.push_back('/'); 1184 push_string(pv->byte_data, p->first); 1185 if (!(p->second.empty())) 1186 { 1187 pv->byte_data.push_back('@'); 1188 push_string(pv->byte_data, p->second); 1189 pv->byte_data.push_back(0); 1190 } 1191 } 1192 } 1193 } 1194 std::unordered_set<property_value*> phandle_set; 1195 for (auto &i : phandles) 1196 { 1197 phandle_set.insert(i); 1198 } 1199 std::vector<property_value*> sorted_phandles; 1200 root->visit([&](node &n) { 1201 for (auto &p : n.properties()) 1202 { 1203 for (auto &v : *p) 1204 { 1205 if (phandle_set.count(&v)) 1206 { 1207 sorted_phandles.push_back(&v); 1208 } 1209 } 1210 } 1211 }); 1212 assert(sorted_phandles.size() == phandles.size()); 1213 1214 uint32_t phandle = 1; 1215 for (auto &i : sorted_phandles) 1216 { 1217 string target_name = i->string_data; 1218 node *target = nullptr; 1219 string possible; 1220 // If the node name is a path, then look it up by following the path, 1221 // otherwise jump directly to the named node. 1222 if (target_name[0] == '/') 1223 { 1224 std::string path; 1225 target = root.get(); 1226 std::istringstream ss(target_name); 1227 string path_element; 1228 // Read the leading / 1229 std::getline(ss, path_element, '/'); 1230 // Iterate over path elements 1231 while (!ss.eof()) 1232 { 1233 path += '/'; 1234 std::getline(ss, path_element, '/'); 1235 std::istringstream nss(path_element); 1236 string node_name, node_address; 1237 std::getline(nss, node_name, '@'); 1238 std::getline(nss, node_address, '@'); 1239 node *next = nullptr; 1240 for (auto &c : target->child_nodes()) 1241 { 1242 if (c->name == node_name) 1243 { 1244 if (c->unit_address == node_address) 1245 { 1246 next = c.get(); 1247 break; 1248 } 1249 else 1250 { 1251 possible = path + c->name; 1252 if (c->unit_address != string()) 1253 { 1254 possible += '@'; 1255 possible += c->unit_address; 1256 } 1257 } 1258 } 1259 } 1260 path += node_name; 1261 if (node_address != string()) 1262 { 1263 path += '@'; 1264 path += node_address; 1265 } 1266 target = next; 1267 if (target == nullptr) 1268 { 1269 break; 1270 } 1271 } 1272 } 1273 else 1274 { 1275 target = node_names[target_name]; 1276 } 1277 if (target == nullptr) 1278 { 1279 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str()); 1280 if (possible != string()) 1281 { 1282 fprintf(stderr, "Possible intended match: %s\n", possible.c_str()); 1283 } 1284 valid = 0; 1285 return; 1286 } 1287 // If there is an existing phandle, use it 1288 property_ptr p = target->get_property("phandle"); 1289 if (p == 0) 1290 { 1291 p = target->get_property("linux,phandle"); 1292 } 1293 if (p == 0) 1294 { 1295 // Otherwise insert a new phandle node 1296 property_value v; 1297 while (used_phandles.find(phandle) != used_phandles.end()) 1298 { 1299 // Note that we only don't need to 1300 // store this phandle in the set, 1301 // because we are monotonically 1302 // increasing the value of phandle and 1303 // so will only ever revisit this value 1304 // if we have used 2^32 phandles, at 1305 // which point our blob won't fit in 1306 // any 32-bit system and we've done 1307 // something badly wrong elsewhere 1308 // already. 1309 phandle++; 1310 } 1311 push_big_endian(v.byte_data, phandle++); 1312 if (phandle_node_name == BOTH || phandle_node_name == LINUX) 1313 { 1314 p.reset(new property("linux,phandle")); 1315 p->add_value(v); 1316 target->add_property(p); 1317 } 1318 if (phandle_node_name == BOTH || phandle_node_name == EPAPR) 1319 { 1320 p.reset(new property("phandle")); 1321 p->add_value(v); 1322 target->add_property(p); 1323 } 1324 } 1325 p->begin()->push_to_buffer(i->byte_data); 1326 assert(i->byte_data.size() == 4); 1327 } 1328 } 1329 1330 1331 void 1332 device_tree::parse_file(text_input_buffer &input, 1333 std::vector<node_ptr> &roots, 1334 bool &read_header) 1335 { 1336 input.next_token(); 1337 // Read the header 1338 if (input.consume("/dts-v1/;")) 1339 { 1340 read_header = true; 1341 } 1342 input.next_token(); 1343 input.next_token(); 1344 if (!read_header) 1345 { 1346 input.parse_error("Expected /dts-v1/; version string"); 1347 } 1348 // Read any memory reservations 1349 while (input.consume("/memreserve/")) 1350 { 1351 unsigned long long start, len; 1352 input.next_token(); 1353 // Read the start and length. 1354 if (!(input.consume_integer_expression(start) && 1355 (input.next_token(), 1356 input.consume_integer_expression(len)))) 1357 { 1358 input.parse_error("Expected size on /memreserve/ node."); 1359 } 1360 input.next_token(); 1361 input.consume(';'); 1362 reservations.push_back(reservation(start, len)); 1363 input.next_token(); 1364 } 1365 while (valid && !input.finished()) 1366 { 1367 node_ptr n; 1368 if (input.consume('/')) 1369 { 1370 input.next_token(); 1371 n = node::parse(input, string(), string_set(), string(), &defines); 1372 } 1373 else if (input.consume('&')) 1374 { 1375 input.next_token(); 1376 string name = input.parse_node_name(); 1377 input.next_token(); 1378 n = node::parse(input, std::move(name), string_set(), string(), &defines); 1379 } 1380 else 1381 { 1382 input.parse_error("Failed to find root node /."); 1383 } 1384 if (n) 1385 { 1386 roots.push_back(std::move(n)); 1387 } 1388 else 1389 { 1390 valid = false; 1391 } 1392 input.next_token(); 1393 } 1394 } 1395 1396 template<class writer> void 1397 device_tree::write(int fd) 1398 { 1399 dtb::string_table st; 1400 dtb::header head; 1401 writer head_writer; 1402 writer reservation_writer; 1403 writer struct_writer; 1404 writer strings_writer; 1405 1406 // Build the reservation table 1407 reservation_writer.write_comment(string("Memory reservations")); 1408 reservation_writer.write_label(string("dt_reserve_map")); 1409 for (auto &i : reservations) 1410 { 1411 reservation_writer.write_comment(string("Reservation start")); 1412 reservation_writer.write_data(i.first); 1413 reservation_writer.write_comment(string("Reservation length")); 1414 reservation_writer.write_data(i.first); 1415 } 1416 // Write n spare reserve map entries, plus the trailing 0. 1417 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++) 1418 { 1419 reservation_writer.write_data((uint64_t)0); 1420 reservation_writer.write_data((uint64_t)0); 1421 } 1422 1423 1424 struct_writer.write_comment(string("Device tree")); 1425 struct_writer.write_label(string("dt_struct_start")); 1426 root->write(struct_writer, st); 1427 struct_writer.write_token(dtb::FDT_END); 1428 struct_writer.write_label(string("dt_struct_end")); 1429 1430 st.write(strings_writer); 1431 // Find the strings size before we stick padding on the end. 1432 // Note: We should possibly use a new writer for the padding. 1433 head.size_dt_strings = strings_writer.size(); 1434 1435 // Stick the padding in the strings writer, but after the 1436 // marker indicating that it's the end. 1437 // Note: We probably should add a padding call to the writer so 1438 // that the asm back end can write padding directives instead 1439 // of a load of 0 bytes. 1440 for (uint32_t i=0 ; i<blob_padding ; i++) 1441 { 1442 strings_writer.write_data((uint8_t)0); 1443 } 1444 head.totalsize = sizeof(head) + strings_writer.size() + 1445 struct_writer.size() + reservation_writer.size(); 1446 while (head.totalsize < minimum_blob_size) 1447 { 1448 head.totalsize++; 1449 strings_writer.write_data((uint8_t)0); 1450 } 1451 head.off_dt_struct = sizeof(head) + reservation_writer.size();; 1452 head.off_dt_strings = head.off_dt_struct + struct_writer.size(); 1453 head.off_mem_rsvmap = sizeof(head); 1454 head.boot_cpuid_phys = boot_cpu; 1455 head.size_dt_struct = struct_writer.size(); 1456 head.write(head_writer); 1457 1458 head_writer.write_to_file(fd); 1459 reservation_writer.write_to_file(fd); 1460 struct_writer.write_to_file(fd); 1461 strings_writer.write_label(string("dt_blob_end")); 1462 strings_writer.write_to_file(fd); 1463 } 1464 1465 node* 1466 device_tree::referenced_node(property_value &v) 1467 { 1468 if (v.is_phandle()) 1469 { 1470 return node_names[v.string_data]; 1471 } 1472 if (v.is_binary()) 1473 { 1474 return used_phandles[v.get_as_uint32()]; 1475 } 1476 return 0; 1477 } 1478 1479 void 1480 device_tree::write_binary(int fd) 1481 { 1482 write<dtb::binary_writer>(fd); 1483 } 1484 1485 void 1486 device_tree::write_asm(int fd) 1487 { 1488 write<dtb::asm_writer>(fd); 1489 } 1490 1491 void 1492 device_tree::write_dts(int fd) 1493 { 1494 FILE *file = fdopen(fd, "w"); 1495 fputs("/dts-v1/;\n\n", file); 1496 1497 if (!reservations.empty()) 1498 { 1499 const char msg[] = "/memreserve/"; 1500 fwrite(msg, sizeof(msg), 1, file); 1501 for (auto &i : reservations) 1502 { 1503 fprintf(file, " %" PRIx64 " %" PRIx64, i.first, i.second); 1504 } 1505 fputs(";\n\n", file); 1506 } 1507 putc('/', file); 1508 putc(' ', file); 1509 root->write_dts(file, 0); 1510 fclose(file); 1511 } 1512 1513 void 1514 device_tree::parse_dtb(const string &fn, FILE *) 1515 { 1516 auto in = input_buffer::buffer_for_file(fn); 1517 if (in == 0) 1518 { 1519 valid = false; 1520 return; 1521 } 1522 input_buffer &input = *in; 1523 dtb::header h; 1524 valid = h.read_dtb(input); 1525 boot_cpu = h.boot_cpuid_phys; 1526 if (h.last_comp_version > 17) 1527 { 1528 fprintf(stderr, "Don't know how to read this version of the device tree blob"); 1529 valid = false; 1530 } 1531 if (!valid) 1532 { 1533 return; 1534 } 1535 input_buffer reservation_map = 1536 input.buffer_from_offset(h.off_mem_rsvmap, 0); 1537 uint64_t start, length; 1538 do 1539 { 1540 if (!(reservation_map.consume_binary(start) && 1541 reservation_map.consume_binary(length))) 1542 { 1543 fprintf(stderr, "Failed to read memory reservation table\n"); 1544 valid = false; 1545 return; 1546 } 1547 } while (!((start == 0) && (length == 0))); 1548 input_buffer struct_table = 1549 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct); 1550 input_buffer strings_table = 1551 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings); 1552 uint32_t token; 1553 if (!(struct_table.consume_binary(token) && 1554 (token == dtb::FDT_BEGIN_NODE))) 1555 { 1556 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n"); 1557 valid = false; 1558 return; 1559 } 1560 root = node::parse_dtb(struct_table, strings_table); 1561 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END))) 1562 { 1563 fprintf(stderr, "Expected FDT_END token after parsing root node.\n"); 1564 valid = false; 1565 return; 1566 } 1567 valid = (root != 0); 1568 } 1569 1570 void 1571 device_tree::parse_dts(const string &fn, FILE *depfile) 1572 { 1573 auto in = input_buffer::buffer_for_file(fn); 1574 if (!in) 1575 { 1576 valid = false; 1577 return; 1578 } 1579 std::vector<node_ptr> roots; 1580 std::unordered_set<string> defnames; 1581 for (auto &i : defines) 1582 { 1583 defnames.insert(i.first); 1584 } 1585 text_input_buffer input(std::move(in), 1586 std::move(defnames), 1587 std::vector<string>(include_paths), 1588 dirname(fn), 1589 depfile); 1590 bool read_header = false; 1591 parse_file(input, roots, read_header); 1592 switch (roots.size()) 1593 { 1594 case 0: 1595 valid = false; 1596 input.parse_error("Failed to find root node /."); 1597 return; 1598 case 1: 1599 root = std::move(roots[0]); 1600 break; 1601 default: 1602 { 1603 root = std::move(roots[0]); 1604 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i) 1605 { 1606 auto &node = *i; 1607 string name = node->name; 1608 if (name == string()) 1609 { 1610 root->merge_node(std::move(node)); 1611 } 1612 else 1613 { 1614 auto existing = node_names.find(name); 1615 if (existing == node_names.end()) 1616 { 1617 collect_names(); 1618 existing = node_names.find(name); 1619 } 1620 if (existing == node_names.end()) 1621 { 1622 fprintf(stderr, "Unable to merge node: %s\n", name.c_str()); 1623 } 1624 else 1625 { 1626 existing->second->merge_node(std::move(node)); 1627 } 1628 } 1629 } 1630 } 1631 } 1632 collect_names(); 1633 resolve_cross_references(); 1634 } 1635 1636 bool device_tree::parse_define(const char *def) 1637 { 1638 char *val = strchr(def, '='); 1639 if (!val) 1640 { 1641 if (strlen(def) != 0) 1642 { 1643 string name(def); 1644 defines[name]; 1645 return true; 1646 } 1647 return false; 1648 } 1649 string name(def, val-def); 1650 string name_copy = name; 1651 val++; 1652 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val))); 1653 text_input_buffer in(std::move(raw), 1654 std::unordered_set<string>(), 1655 std::vector<string>(), 1656 std::string(), 1657 nullptr); 1658 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false); 1659 if (p) 1660 defines[name] = p; 1661 return (bool)p; 1662 } 1663 1664 } // namespace fdt 1665 1666 } // namespace dtc 1667 1668