1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 David Chisnall 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD$ 33 */ 34 35 #define __STDC_LIMIT_MACROS 1 36 37 #include "fdt.hh" 38 #include "dtb.hh" 39 40 #include <algorithm> 41 #include <sstream> 42 43 #include <ctype.h> 44 #include <fcntl.h> 45 #include <inttypes.h> 46 #include <libgen.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <errno.h> 54 55 using std::string; 56 57 namespace dtc 58 { 59 60 namespace fdt 61 { 62 63 uint32_t 64 property_value::get_as_uint32() 65 { 66 if (byte_data.size() != 4) 67 { 68 return 0; 69 } 70 uint32_t v = 0; 71 v &= byte_data[0] << 24; 72 v &= byte_data[1] << 16; 73 v &= byte_data[2] << 8; 74 v &= byte_data[3] << 0; 75 return v; 76 } 77 78 void 79 property_value::push_to_buffer(byte_buffer &buffer) 80 { 81 if (!byte_data.empty()) 82 { 83 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end()); 84 } 85 else 86 { 87 push_string(buffer, string_data, true); 88 // Trailing nul 89 buffer.push_back(0); 90 } 91 } 92 93 void 94 property_value::write_dts(FILE *file) 95 { 96 resolve_type(); 97 switch (type) 98 { 99 default: 100 assert(0 && "Invalid type"); 101 case STRING: 102 case STRING_LIST: 103 case CROSS_REFERENCE: 104 write_as_string(file); 105 break; 106 case PHANDLE: 107 write_as_cells(file); 108 break; 109 case BINARY: 110 if (byte_data.size() % 4 == 0) 111 { 112 write_as_cells(file); 113 break; 114 } 115 write_as_bytes(file); 116 break; 117 } 118 } 119 120 void 121 property_value::resolve_type() 122 { 123 if (type != UNKNOWN) 124 { 125 return; 126 } 127 if (byte_data.empty()) 128 { 129 type = STRING; 130 return; 131 } 132 if (byte_data.back() == 0) 133 { 134 bool is_all_printable = true; 135 int nuls = 0; 136 int bytes = 0; 137 bool lastWasNull = false; 138 for (auto i : byte_data) 139 { 140 bytes++; 141 is_all_printable &= (i == '\0') || isprint(i); 142 if (i == '\0') 143 { 144 // If there are two nulls in a row, then we're probably binary. 145 if (lastWasNull) 146 { 147 type = BINARY; 148 return; 149 } 150 nuls++; 151 lastWasNull = true; 152 } 153 else 154 { 155 lastWasNull = false; 156 } 157 if (!is_all_printable) 158 { 159 break; 160 } 161 } 162 if ((is_all_printable && (bytes > nuls)) || bytes == 0) 163 { 164 type = STRING; 165 if (nuls > 1) 166 { 167 type = STRING_LIST; 168 } 169 return; 170 } 171 } 172 type = BINARY; 173 } 174 175 size_t 176 property_value::size() 177 { 178 if (!byte_data.empty()) 179 { 180 return byte_data.size(); 181 } 182 return string_data.size() + 1; 183 } 184 185 void 186 property_value::write_as_string(FILE *file) 187 { 188 putc('"', file); 189 if (byte_data.empty()) 190 { 191 fputs(string_data.c_str(), file); 192 } 193 else 194 { 195 bool hasNull = (byte_data.back() == '\0'); 196 // Remove trailing null bytes from the string before printing as dts. 197 if (hasNull) 198 { 199 byte_data.pop_back(); 200 } 201 for (auto i : byte_data) 202 { 203 // FIXME Escape tabs, newlines, and so on. 204 if (i == '\0') 205 { 206 fputs("\", \"", file); 207 continue; 208 } 209 putc(i, file); 210 } 211 if (hasNull) 212 { 213 byte_data.push_back('\0'); 214 } 215 } 216 putc('"', file); 217 } 218 219 void 220 property_value::write_as_cells(FILE *file) 221 { 222 putc('<', file); 223 assert((byte_data.size() % 4) == 0); 224 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i) 225 { 226 uint32_t v = 0; 227 v = (v << 8) | *i; 228 ++i; 229 v = (v << 8) | *i; 230 ++i; 231 v = (v << 8) | *i; 232 ++i; 233 v = (v << 8) | *i; 234 fprintf(file, "0x%" PRIx32, v); 235 if (i+1 != e) 236 { 237 putc(' ', file); 238 } 239 } 240 putc('>', file); 241 } 242 243 void 244 property_value::write_as_bytes(FILE *file) 245 { 246 putc('[', file); 247 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++) 248 { 249 fprintf(file, "%02hhx", *i); 250 if (i+1 != e) 251 { 252 putc(' ', file); 253 } 254 } 255 putc(']', file); 256 } 257 258 void 259 property::parse_string(text_input_buffer &input) 260 { 261 property_value v; 262 assert(*input == '"'); 263 ++input; 264 std::vector<char> bytes; 265 bool isEscaped = false; 266 while (char c = *input) 267 { 268 if (c == '"' && !isEscaped) 269 { 270 input.consume('"'); 271 break; 272 } 273 isEscaped = (c == '\\'); 274 bytes.push_back(c); 275 ++input; 276 } 277 v.string_data = string(bytes.begin(), bytes.end()); 278 values.push_back(v); 279 } 280 281 void 282 property::parse_cells(text_input_buffer &input, int cell_size) 283 { 284 assert(*input == '<'); 285 ++input; 286 property_value v; 287 input.next_token(); 288 while (!input.consume('>')) 289 { 290 input.next_token(); 291 // If this is a phandle then we need to get the name of the 292 // referenced node 293 if (input.consume('&')) 294 { 295 if (cell_size != 32) 296 { 297 input.parse_error("reference only permitted in 32-bit arrays"); 298 valid = false; 299 return; 300 } 301 input.next_token(); 302 string referenced; 303 if (!input.consume('{')) 304 { 305 referenced = input.parse_node_name(); 306 } 307 else 308 { 309 referenced = input.parse_to('}'); 310 input.consume('}'); 311 } 312 if (referenced.empty()) 313 { 314 input.parse_error("Expected node name"); 315 valid = false; 316 return; 317 } 318 input.next_token(); 319 // If we already have some bytes, make the phandle a 320 // separate component. 321 if (!v.byte_data.empty()) 322 { 323 values.push_back(v); 324 v = property_value(); 325 } 326 v.string_data = referenced; 327 v.type = property_value::PHANDLE; 328 values.push_back(v); 329 v = property_value(); 330 } 331 else 332 { 333 //FIXME: We should support labels in the middle 334 //of these, but we don't. 335 unsigned long long val; 336 if (!input.consume_integer_expression(val)) 337 { 338 // FIXME: Distinguish invalid syntax from a 339 // number that cannot be represented in an 340 // unsigned long long. 341 input.parse_error("Expected numbers in array of cells"); 342 valid = false; 343 return; 344 } 345 // FIXME: No sign information available, so cannot 346 // distinguish small negative values from large 347 // positive ones, and thus we have to conservatively 348 // permit anything that looks like a sign-extended 349 // negative integer. 350 if (cell_size < 64 && val >= (1ull << cell_size) && 351 (val | ((1ull << (cell_size - 1)) - 1)) != 352 std::numeric_limits<unsigned long long>::max()) 353 { 354 std::string msg = "Value does not fit in a " + 355 std::to_string(cell_size) + "-bit cell"; 356 input.parse_error(msg.c_str()); 357 valid = false; 358 return; 359 } 360 switch (cell_size) 361 { 362 case 8: 363 v.byte_data.push_back(val); 364 break; 365 case 16: 366 push_big_endian(v.byte_data, (uint16_t)val); 367 break; 368 case 32: 369 push_big_endian(v.byte_data, (uint32_t)val); 370 break; 371 case 64: 372 push_big_endian(v.byte_data, (uint64_t)val); 373 break; 374 default: 375 assert(0 && "Invalid cell size!"); 376 } 377 input.next_token(); 378 } 379 } 380 // Don't store an empty string value here. 381 if (v.byte_data.size() > 0) 382 { 383 values.push_back(v); 384 } 385 } 386 387 void 388 property::parse_bytes(text_input_buffer &input) 389 { 390 assert(*input == '['); 391 ++input; 392 property_value v; 393 input.next_token(); 394 while (!input.consume(']')) 395 { 396 { 397 //FIXME: We should support 398 //labels in the middle of 399 //these, but we don't. 400 uint8_t val; 401 if (!input.consume_hex_byte(val)) 402 { 403 input.parse_error("Expected hex bytes in array of bytes"); 404 valid = false; 405 return; 406 } 407 v.byte_data.push_back(val); 408 input.next_token(); 409 } 410 } 411 values.push_back(v); 412 } 413 414 void 415 property::parse_reference(text_input_buffer &input) 416 { 417 assert(*input == '&'); 418 ++input; 419 input.next_token(); 420 property_value v; 421 v.string_data = input.parse_node_name(); 422 if (v.string_data.empty()) 423 { 424 input.parse_error("Expected node name"); 425 valid = false; 426 return; 427 } 428 v.type = property_value::CROSS_REFERENCE; 429 values.push_back(v); 430 } 431 432 property::property(input_buffer &structs, input_buffer &strings) 433 { 434 uint32_t name_offset; 435 uint32_t length; 436 valid = structs.consume_binary(length) && 437 structs.consume_binary(name_offset); 438 if (!valid) 439 { 440 fprintf(stderr, "Failed to read property\n"); 441 return; 442 } 443 // Find the name 444 input_buffer name_buffer = strings.buffer_from_offset(name_offset); 445 if (name_buffer.finished()) 446 { 447 fprintf(stderr, "Property name offset %" PRIu32 448 " is past the end of the strings table\n", 449 name_offset); 450 valid = false; 451 return; 452 } 453 key = name_buffer.parse_to(0); 454 455 // If we're empty, do not push anything as value. 456 if (!length) 457 return; 458 459 // Read the value 460 uint8_t byte; 461 property_value v; 462 for (uint32_t i=0 ; i<length ; i++) 463 { 464 if (!(valid = structs.consume_binary(byte))) 465 { 466 fprintf(stderr, "Failed to read property value\n"); 467 return; 468 } 469 v.byte_data.push_back(byte); 470 } 471 values.push_back(v); 472 } 473 474 void property::parse_define(text_input_buffer &input, define_map *defines) 475 { 476 input.consume('$'); 477 if (!defines) 478 { 479 input.parse_error("No predefined properties to match name\n"); 480 valid = false; 481 return; 482 } 483 string name = input.parse_property_name(); 484 define_map::iterator found; 485 if ((name == string()) || 486 ((found = defines->find(name)) == defines->end())) 487 { 488 input.parse_error("Undefined property name\n"); 489 valid = false; 490 return; 491 } 492 values.push_back((*found).second->values[0]); 493 } 494 495 property::property(text_input_buffer &input, 496 string &&k, 497 string_set &&l, 498 bool semicolonTerminated, 499 define_map *defines) : key(k), labels(l), valid(true) 500 { 501 do { 502 input.next_token(); 503 switch (*input) 504 { 505 case '$': 506 { 507 parse_define(input, defines); 508 if (valid) 509 { 510 break; 511 } 512 } 513 [[fallthrough]]; 514 default: 515 input.parse_error("Invalid property value."); 516 valid = false; 517 return; 518 case '/': 519 { 520 if (input.consume("/incbin/(\"")) 521 { 522 auto loc = input.location(); 523 std::string filename = input.parse_to('"'); 524 if (!(valid = input.consume('"'))) 525 { 526 loc.report_error("Syntax error, expected '\"' to terminate /incbin/("); 527 return; 528 } 529 property_value v; 530 if (!(valid = input.read_binary_file(filename, v.byte_data))) 531 { 532 input.parse_error("Cannot open binary include file"); 533 return; 534 } 535 if (!(valid &= input.consume(')'))) 536 { 537 input.parse_error("Syntax error, expected ')' to terminate /incbin/("); 538 return; 539 } 540 values.push_back(v); 541 break; 542 } 543 unsigned long long bits = 0; 544 valid = input.consume("/bits/"); 545 input.next_token(); 546 valid &= input.consume_integer(bits); 547 if ((bits != 8) && 548 (bits != 16) && 549 (bits != 32) && 550 (bits != 64)) { 551 input.parse_error("Invalid size for elements"); 552 valid = false; 553 } 554 if (!valid) return; 555 input.next_token(); 556 if (*input != '<') 557 { 558 input.parse_error("/bits/ directive is only valid on arrays"); 559 valid = false; 560 return; 561 } 562 parse_cells(input, bits); 563 break; 564 } 565 case '"': 566 parse_string(input); 567 break; 568 case '<': 569 parse_cells(input, 32); 570 break; 571 case '[': 572 parse_bytes(input); 573 break; 574 case '&': 575 parse_reference(input); 576 break; 577 case ';': 578 { 579 break; 580 } 581 } 582 input.next_token(); 583 } while (input.consume(',')); 584 if (semicolonTerminated && !input.consume(';')) 585 { 586 input.parse_error("Expected ; at end of property"); 587 valid = false; 588 } 589 } 590 591 property_ptr 592 property::parse_dtb(input_buffer &structs, input_buffer &strings) 593 { 594 property_ptr p(new property(structs, strings)); 595 if (!p->valid) 596 { 597 p = nullptr; 598 } 599 return p; 600 } 601 602 property_ptr 603 property::parse(text_input_buffer &input, string &&key, string_set &&label, 604 bool semicolonTerminated, define_map *defines) 605 { 606 property_ptr p(new property(input, 607 std::move(key), 608 std::move(label), 609 semicolonTerminated, 610 defines)); 611 if (!p->valid) 612 { 613 p = nullptr; 614 } 615 return p; 616 } 617 618 void 619 property::write(dtb::output_writer &writer, dtb::string_table &strings) 620 { 621 writer.write_token(dtb::FDT_PROP); 622 byte_buffer value_buffer; 623 for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 624 { 625 i->push_to_buffer(value_buffer); 626 } 627 writer.write_data((uint32_t)value_buffer.size()); 628 writer.write_comment(key); 629 writer.write_data(strings.add_string(key)); 630 writer.write_data(value_buffer); 631 } 632 633 bool 634 property_value::try_to_merge(property_value &other) 635 { 636 resolve_type(); 637 switch (type) 638 { 639 case UNKNOWN: 640 __builtin_unreachable(); 641 assert(0); 642 return false; 643 case EMPTY: 644 *this = other; 645 [[fallthrough]]; 646 case STRING: 647 case STRING_LIST: 648 case CROSS_REFERENCE: 649 return false; 650 case PHANDLE: 651 case BINARY: 652 if (other.type == PHANDLE || other.type == BINARY) 653 { 654 type = BINARY; 655 byte_data.insert(byte_data.end(), other.byte_data.begin(), 656 other.byte_data.end()); 657 return true; 658 } 659 } 660 return false; 661 } 662 663 void 664 property::write_dts(FILE *file, int indent) 665 { 666 for (int i=0 ; i<indent ; i++) 667 { 668 putc('\t', file); 669 } 670 #ifdef PRINT_LABELS 671 for (auto &l : labels) 672 { 673 fputs(l.c_str(), file); 674 fputs(": ", file); 675 } 676 #endif 677 if (key != string()) 678 { 679 fputs(key.c_str(), file); 680 } 681 if (!values.empty()) 682 { 683 std::vector<property_value> *vals = &values; 684 std::vector<property_value> v; 685 // If we've got multiple values then try to merge them all together. 686 if (values.size() > 1) 687 { 688 vals = &v; 689 v.push_back(values.front()); 690 for (auto i=(++begin()), e=end() ; i!=e ; ++i) 691 { 692 if (!v.back().try_to_merge(*i)) 693 { 694 v.push_back(*i); 695 } 696 } 697 } 698 fputs(" = ", file); 699 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i) 700 { 701 i->write_dts(file); 702 if (i+1 != e) 703 { 704 putc(',', file); 705 putc(' ', file); 706 } 707 } 708 } 709 fputs(";\n", file); 710 } 711 712 size_t 713 property::offset_of_value(property_value &val) 714 { 715 size_t off = 0; 716 for (auto &v : values) 717 { 718 if (&v == &val) 719 { 720 return off; 721 } 722 off += v.size(); 723 } 724 return -1; 725 } 726 727 string 728 node::parse_name(text_input_buffer &input, bool &is_property, const char *error) 729 { 730 if (!valid) 731 { 732 return string(); 733 } 734 input.next_token(); 735 if (is_property) 736 { 737 return input.parse_property_name(); 738 } 739 string n = input.parse_node_or_property_name(is_property); 740 if (n.empty()) 741 { 742 if (n.empty()) 743 { 744 input.parse_error(error); 745 valid = false; 746 } 747 } 748 return n; 749 } 750 751 node::visit_behavior 752 node::visit(std::function<visit_behavior(node&, node*)> fn, node *parent) 753 { 754 visit_behavior behavior; 755 behavior = fn(*this, parent); 756 if (behavior == VISIT_BREAK) 757 { 758 return VISIT_BREAK; 759 } 760 else if (behavior != VISIT_CONTINUE) 761 { 762 for (auto &&c : children) 763 { 764 behavior = c->visit(fn, this); 765 // Any status other than VISIT_RECURSE stops our execution and 766 // bubbles up to our caller. The caller may then either continue 767 // visiting nodes that are siblings to this one or completely halt 768 // visiting. 769 if (behavior != VISIT_RECURSE) 770 { 771 return behavior; 772 } 773 } 774 } 775 // Continue recursion by default 776 return VISIT_RECURSE; 777 } 778 779 node::node(input_buffer &structs, input_buffer &strings) : valid(true) 780 { 781 std::vector<char> bytes; 782 while (structs[0] != '\0' && structs[0] != '@') 783 { 784 bytes.push_back(structs[0]); 785 ++structs; 786 } 787 name = string(bytes.begin(), bytes.end()); 788 bytes.clear(); 789 if (structs[0] == '@') 790 { 791 ++structs; 792 while (structs[0] != '\0') 793 { 794 bytes.push_back(structs[0]); 795 ++structs; 796 } 797 unit_address = string(bytes.begin(), bytes.end()); 798 } 799 ++structs; 800 uint32_t token; 801 while (structs.consume_binary(token)) 802 { 803 switch (token) 804 { 805 default: 806 fprintf(stderr, "Unexpected token 0x%" PRIx32 807 " while parsing node.\n", token); 808 valid = false; 809 return; 810 // Child node, parse it. 811 case dtb::FDT_BEGIN_NODE: 812 { 813 node_ptr child = node::parse_dtb(structs, strings); 814 if (child == 0) 815 { 816 valid = false; 817 return; 818 } 819 children.push_back(std::move(child)); 820 break; 821 } 822 // End of this node, no errors. 823 case dtb::FDT_END_NODE: 824 return; 825 // Property, parse it. 826 case dtb::FDT_PROP: 827 { 828 property_ptr prop = property::parse_dtb(structs, strings); 829 if (prop == 0) 830 { 831 valid = false; 832 return; 833 } 834 props.push_back(prop); 835 break; 836 } 837 break; 838 // End of structs table. Should appear after 839 // the end of the last node. 840 case dtb::FDT_END: 841 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n"); 842 valid = false; 843 return; 844 // NOPs are padding. Ignore them. 845 case dtb::FDT_NOP: 846 break; 847 } 848 } 849 fprintf(stderr, "Failed to read token from structs table while parsing node.\n"); 850 valid = false; 851 return; 852 } 853 854 855 node::node(const string &n, 856 const std::vector<property_ptr> &p) 857 : name(n) 858 { 859 props.insert(props.begin(), p.begin(), p.end()); 860 } 861 862 node_ptr node::create_special_node(const string &name, 863 const std::vector<property_ptr> &props) 864 { 865 node_ptr n(new node(name, props)); 866 return n; 867 } 868 869 node::node(text_input_buffer &input, 870 device_tree &tree, 871 string &&n, 872 std::unordered_set<string> &&l, 873 string &&a, 874 define_map *defines) 875 : labels(l), name(n), unit_address(a), valid(true) 876 { 877 if (!input.consume('{')) 878 { 879 input.parse_error("Expected { to start new device tree node.\n"); 880 } 881 input.next_token(); 882 while (valid && !input.consume('}')) 883 { 884 // flag set if we find any characters that are only in 885 // the property name character set, not the node 886 bool is_property = false; 887 // flag set if our node is marked as /omit-if-no-ref/ to be 888 // garbage collected later if nothing references it 889 bool marked_omit_if_no_ref = false; 890 string child_name, child_address; 891 std::unordered_set<string> child_labels; 892 auto parse_delete = [&](const char *expected, bool at) 893 { 894 if (child_name == string()) 895 { 896 input.parse_error(expected); 897 valid = false; 898 return; 899 } 900 input.next_token(); 901 if (at && input.consume('@')) 902 { 903 child_name += '@'; 904 child_name += parse_name(input, is_property, "Expected unit address"); 905 } 906 if (!input.consume(';')) 907 { 908 input.parse_error("Expected semicolon"); 909 valid = false; 910 return; 911 } 912 input.next_token(); 913 }; 914 if (input.consume("/delete-node/")) 915 { 916 input.next_token(); 917 child_name = input.parse_node_name(); 918 parse_delete("Expected node name", true); 919 if (valid) 920 { 921 deleted_children.insert(child_name); 922 } 923 continue; 924 } 925 if (input.consume("/delete-property/")) 926 { 927 input.next_token(); 928 child_name = input.parse_property_name(); 929 parse_delete("Expected property name", false); 930 if (valid) 931 { 932 deleted_props.insert(child_name); 933 } 934 continue; 935 } 936 if (input.consume("/omit-if-no-ref/")) 937 { 938 input.next_token(); 939 marked_omit_if_no_ref = true; 940 tree.set_needs_garbage_collection(); 941 } 942 child_name = parse_name(input, is_property, 943 "Expected property or node name"); 944 while (input.consume(':')) 945 { 946 // Node labels can contain any characters? The 947 // spec doesn't say, so we guess so... 948 is_property = false; 949 child_labels.insert(std::move(child_name)); 950 child_name = parse_name(input, is_property, "Expected property or node name"); 951 } 952 if (input.consume('@')) 953 { 954 child_address = parse_name(input, is_property, "Expected unit address"); 955 } 956 if (!valid) 957 { 958 return; 959 } 960 input.next_token(); 961 // If we're parsing a property, then we must actually do that. 962 if (input.consume('=')) 963 { 964 property_ptr p = property::parse(input, std::move(child_name), 965 std::move(child_labels), true, defines); 966 if (p == 0) 967 { 968 valid = false; 969 } 970 else 971 { 972 props.push_back(p); 973 } 974 } 975 else if (!is_property && *input == ('{')) 976 { 977 node_ptr child = node::parse(input, tree, std::move(child_name), 978 std::move(child_labels), std::move(child_address), defines); 979 if (child) 980 { 981 child->omit_if_no_ref = marked_omit_if_no_ref; 982 children.push_back(std::move(child)); 983 } 984 else 985 { 986 valid = false; 987 } 988 } 989 else if (input.consume(';')) 990 { 991 props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels)))); 992 } 993 else 994 { 995 input.parse_error("Error parsing property. Expected property value"); 996 valid = false; 997 } 998 input.next_token(); 999 } 1000 input.next_token(); 1001 input.consume(';'); 1002 } 1003 1004 bool 1005 node::cmp_properties(property_ptr &p1, property_ptr &p2) 1006 { 1007 return p1->get_key() < p2->get_key(); 1008 } 1009 1010 bool 1011 node::cmp_children(node_ptr &c1, node_ptr &c2) 1012 { 1013 if (c1->name == c2->name) 1014 { 1015 return c1->unit_address < c2->unit_address; 1016 } 1017 return c1->name < c2->name; 1018 } 1019 1020 void 1021 node::sort() 1022 { 1023 std::sort(property_begin(), property_end(), cmp_properties); 1024 std::sort(child_begin(), child_end(), cmp_children); 1025 for (auto &c : child_nodes()) 1026 { 1027 c->sort(); 1028 } 1029 } 1030 1031 node_ptr 1032 node::parse(text_input_buffer &input, 1033 device_tree &tree, 1034 string &&name, 1035 string_set &&label, 1036 string &&address, 1037 define_map *defines) 1038 { 1039 node_ptr n(new node(input, 1040 tree, 1041 std::move(name), 1042 std::move(label), 1043 std::move(address), 1044 defines)); 1045 if (!n->valid) 1046 { 1047 n = 0; 1048 } 1049 return n; 1050 } 1051 1052 node_ptr 1053 node::parse_dtb(input_buffer &structs, input_buffer &strings) 1054 { 1055 node_ptr n(new node(structs, strings)); 1056 if (!n->valid) 1057 { 1058 n = 0; 1059 } 1060 return n; 1061 } 1062 1063 property_ptr 1064 node::get_property(const string &key) 1065 { 1066 for (auto &i : props) 1067 { 1068 if (i->get_key() == key) 1069 { 1070 return i; 1071 } 1072 } 1073 return 0; 1074 } 1075 1076 void 1077 node::merge_node(node_ptr &other) 1078 { 1079 for (auto &l : other->labels) 1080 { 1081 labels.insert(l); 1082 } 1083 children.erase(std::remove_if(children.begin(), children.end(), 1084 [&](const node_ptr &p) { 1085 string full_name = p->name; 1086 if (p->unit_address != string()) 1087 { 1088 full_name += '@'; 1089 full_name += p->unit_address; 1090 } 1091 if (other->deleted_children.count(full_name) > 0) 1092 { 1093 other->deleted_children.erase(full_name); 1094 return true; 1095 } 1096 return false; 1097 }), children.end()); 1098 props.erase(std::remove_if(props.begin(), props.end(), 1099 [&](const property_ptr &p) { 1100 if (other->deleted_props.count(p->get_key()) > 0) 1101 { 1102 other->deleted_props.erase(p->get_key()); 1103 return true; 1104 } 1105 return false; 1106 }), props.end()); 1107 // Note: this is an O(n*m) operation. It might be sensible to 1108 // optimise this if we find that there are nodes with very 1109 // large numbers of properties, but for typical usage the 1110 // entire vector will fit (easily) into cache, so iterating 1111 // over it repeatedly isn't that expensive. 1112 for (auto &p : other->properties()) 1113 { 1114 bool found = false; 1115 for (auto &mp : properties()) 1116 { 1117 if (mp->get_key() == p->get_key()) 1118 { 1119 mp = p; 1120 found = true; 1121 break; 1122 } 1123 } 1124 if (!found) 1125 { 1126 add_property(p); 1127 } 1128 } 1129 for (auto &c : other->children) 1130 { 1131 bool found = false; 1132 for (auto &i : children) 1133 { 1134 if (i->name == c->name && i->unit_address == c->unit_address) 1135 { 1136 i->merge_node(c); 1137 found = true; 1138 break; 1139 } 1140 } 1141 if (!found) 1142 { 1143 children.push_back(std::move(c)); 1144 } 1145 } 1146 } 1147 1148 void 1149 node::write(dtb::output_writer &writer, dtb::string_table &strings) 1150 { 1151 writer.write_token(dtb::FDT_BEGIN_NODE); 1152 byte_buffer name_buffer; 1153 push_string(name_buffer, name); 1154 if (unit_address != string()) 1155 { 1156 name_buffer.push_back('@'); 1157 push_string(name_buffer, unit_address); 1158 } 1159 writer.write_comment(name); 1160 writer.write_data(name_buffer); 1161 writer.write_data((uint8_t)0); 1162 for (auto p : properties()) 1163 { 1164 p->write(writer, strings); 1165 } 1166 for (auto &c : child_nodes()) 1167 { 1168 c->write(writer, strings); 1169 } 1170 writer.write_token(dtb::FDT_END_NODE); 1171 } 1172 1173 void 1174 node::write_dts(FILE *file, int indent) 1175 { 1176 for (int i=0 ; i<indent ; i++) 1177 { 1178 putc('\t', file); 1179 } 1180 #ifdef PRINT_LABELS 1181 for (auto &label : labels) 1182 { 1183 fprintf(file, "%s: ", label.c_str()); 1184 } 1185 #endif 1186 if (name != string()) 1187 { 1188 fputs(name.c_str(), file); 1189 } 1190 if (unit_address != string()) 1191 { 1192 putc('@', file); 1193 fputs(unit_address.c_str(), file); 1194 } 1195 fputs(" {\n\n", file); 1196 for (auto p : properties()) 1197 { 1198 p->write_dts(file, indent+1); 1199 } 1200 for (auto &c : child_nodes()) 1201 { 1202 c->write_dts(file, indent+1); 1203 } 1204 for (int i=0 ; i<indent ; i++) 1205 { 1206 putc('\t', file); 1207 } 1208 fputs("};\n", file); 1209 } 1210 1211 void 1212 device_tree::collect_names_recursive(node_ptr &n, node_path &path) 1213 { 1214 path.push_back(std::make_pair(n->name, n->unit_address)); 1215 for (const string &name : n->labels) 1216 { 1217 if (name != string()) 1218 { 1219 auto iter = node_names.find(name); 1220 if (iter == node_names.end()) 1221 { 1222 node_names.insert(std::make_pair(name, n.get())); 1223 node_paths.insert(std::make_pair(name, path)); 1224 ordered_node_paths.push_back({name, path}); 1225 } 1226 else 1227 { 1228 node_names.erase(iter); 1229 auto i = node_paths.find(name); 1230 if (i != node_paths.end()) 1231 { 1232 node_paths.erase(name); 1233 } 1234 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str()); 1235 } 1236 } 1237 } 1238 for (auto &c : n->child_nodes()) 1239 { 1240 collect_names_recursive(c, path); 1241 } 1242 // Now we collect the phandles and properties that reference 1243 // other nodes. 1244 for (auto &p : n->properties()) 1245 { 1246 for (auto &v : *p) 1247 { 1248 if (v.is_phandle()) 1249 { 1250 fixups.push_back({path, p, v}); 1251 } 1252 if (v.is_cross_reference()) 1253 { 1254 cross_references.push_back(&v); 1255 } 1256 } 1257 if ((p->get_key() == "phandle") || 1258 (p->get_key() == "linux,phandle")) 1259 { 1260 if (p->begin()->byte_data.size() != 4) 1261 { 1262 fprintf(stderr, "Invalid phandle value for node %s. Should be a 4-byte value.\n", n->name.c_str()); 1263 valid = false; 1264 } 1265 else 1266 { 1267 uint32_t phandle = p->begin()->get_as_uint32(); 1268 used_phandles.insert(std::make_pair(phandle, n.get())); 1269 } 1270 } 1271 } 1272 path.pop_back(); 1273 } 1274 1275 void 1276 device_tree::collect_names() 1277 { 1278 node_path p; 1279 node_names.clear(); 1280 node_paths.clear(); 1281 ordered_node_paths.clear(); 1282 cross_references.clear(); 1283 fixups.clear(); 1284 collect_names_recursive(root, p); 1285 } 1286 1287 property_ptr 1288 device_tree::assign_phandle(node *n, uint32_t &phandle) 1289 { 1290 // If there is an existing phandle, use it 1291 property_ptr p = n->get_property("phandle"); 1292 if (p == 0) 1293 { 1294 p = n->get_property("linux,phandle"); 1295 } 1296 if (p == 0) 1297 { 1298 // Otherwise insert a new phandle node 1299 property_value v; 1300 while (used_phandles.find(phandle) != used_phandles.end()) 1301 { 1302 // Note that we only don't need to 1303 // store this phandle in the set, 1304 // because we are monotonically 1305 // increasing the value of phandle and 1306 // so will only ever revisit this value 1307 // if we have used 2^32 phandles, at 1308 // which point our blob won't fit in 1309 // any 32-bit system and we've done 1310 // something badly wrong elsewhere 1311 // already. 1312 phandle++; 1313 } 1314 push_big_endian(v.byte_data, phandle++); 1315 if (phandle_node_name == BOTH || phandle_node_name == LINUX) 1316 { 1317 p.reset(new property("linux,phandle")); 1318 p->add_value(v); 1319 n->add_property(p); 1320 } 1321 if (phandle_node_name == BOTH || phandle_node_name == EPAPR) 1322 { 1323 p.reset(new property("phandle")); 1324 p->add_value(v); 1325 n->add_property(p); 1326 } 1327 } 1328 1329 return (p); 1330 } 1331 1332 void 1333 device_tree::assign_phandles(node_ptr &n, uint32_t &next) 1334 { 1335 if (!n->labels.empty()) 1336 { 1337 assign_phandle(n.get(), next); 1338 } 1339 1340 for (auto &c : n->child_nodes()) 1341 { 1342 assign_phandles(c, next); 1343 } 1344 } 1345 1346 void 1347 device_tree::resolve_cross_references(uint32_t &phandle) 1348 { 1349 for (auto *pv : cross_references) 1350 { 1351 node_path path = node_paths[pv->string_data]; 1352 auto p = path.begin(); 1353 auto pe = path.end(); 1354 if (p != pe) 1355 { 1356 // Skip the first name in the path. It's always "", and implicitly / 1357 for (++p ; p!=pe ; ++p) 1358 { 1359 pv->byte_data.push_back('/'); 1360 push_string(pv->byte_data, p->first); 1361 if (!(p->second.empty())) 1362 { 1363 pv->byte_data.push_back('@'); 1364 push_string(pv->byte_data, p->second); 1365 } 1366 } 1367 pv->byte_data.push_back(0); 1368 } 1369 } 1370 std::unordered_map<property_value*, fixup&> phandle_set; 1371 for (auto &i : fixups) 1372 { 1373 phandle_set.insert({&i.val, i}); 1374 } 1375 std::vector<std::reference_wrapper<fixup>> sorted_phandles; 1376 root->visit([&](node &n, node *) { 1377 for (auto &p : n.properties()) 1378 { 1379 for (auto &v : *p) 1380 { 1381 auto i = phandle_set.find(&v); 1382 if (i != phandle_set.end()) 1383 { 1384 sorted_phandles.push_back(i->second); 1385 } 1386 } 1387 } 1388 // Allow recursion 1389 return node::VISIT_RECURSE; 1390 }, nullptr); 1391 assert(sorted_phandles.size() == fixups.size()); 1392 for (auto &i : sorted_phandles) 1393 { 1394 string target_name = i.get().val.string_data; 1395 node *target = nullptr; 1396 string possible; 1397 // If the node name is a path, then look it up by following the path, 1398 // otherwise jump directly to the named node. 1399 if (target_name[0] == '/') 1400 { 1401 string path; 1402 target = root.get(); 1403 std::istringstream ss(target_name); 1404 string path_element; 1405 // Read the leading / 1406 std::getline(ss, path_element, '/'); 1407 // Iterate over path elements 1408 while (!ss.eof()) 1409 { 1410 path += '/'; 1411 std::getline(ss, path_element, '/'); 1412 std::istringstream nss(path_element); 1413 string node_name, node_address; 1414 std::getline(nss, node_name, '@'); 1415 std::getline(nss, node_address, '@'); 1416 node *next = nullptr; 1417 for (auto &c : target->child_nodes()) 1418 { 1419 if (c->name == node_name) 1420 { 1421 if (c->unit_address == node_address) 1422 { 1423 next = c.get(); 1424 break; 1425 } 1426 else 1427 { 1428 possible = path + c->name; 1429 if (c->unit_address != string()) 1430 { 1431 possible += '@'; 1432 possible += c->unit_address; 1433 } 1434 } 1435 } 1436 } 1437 path += node_name; 1438 if (node_address != string()) 1439 { 1440 path += '@'; 1441 path += node_address; 1442 } 1443 target = next; 1444 if (target == nullptr) 1445 { 1446 break; 1447 } 1448 } 1449 } 1450 else 1451 { 1452 target = node_names[target_name]; 1453 } 1454 if (target == nullptr) 1455 { 1456 if (is_plugin) 1457 { 1458 unresolved_fixups.push_back(i); 1459 continue; 1460 } 1461 else 1462 { 1463 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str()); 1464 if (possible != string()) 1465 { 1466 fprintf(stderr, "Possible intended match: %s\n", possible.c_str()); 1467 } 1468 valid = 0; 1469 return; 1470 } 1471 } 1472 // If there is an existing phandle, use it 1473 property_ptr p = assign_phandle(target, phandle); 1474 p->begin()->push_to_buffer(i.get().val.byte_data); 1475 assert(i.get().val.byte_data.size() == 4); 1476 } 1477 } 1478 1479 bool 1480 device_tree::garbage_collect_marked_nodes() 1481 { 1482 std::unordered_set<node*> previously_referenced_nodes; 1483 std::unordered_set<node*> newly_referenced_nodes; 1484 1485 auto mark_referenced_nodes_used = [&](node &n) 1486 { 1487 for (auto &p : n.properties()) 1488 { 1489 for (auto &v : *p) 1490 { 1491 if (v.is_phandle()) 1492 { 1493 node *nx = node_names[v.string_data]; 1494 if (nx == nullptr) 1495 { 1496 // Try it again, but as a path 1497 for (auto &s : node_paths) 1498 { 1499 if (v.string_data == s.second.to_string()) 1500 { 1501 nx = node_names[s.first]; 1502 break; 1503 } 1504 } 1505 } 1506 if (nx == nullptr) 1507 { 1508 // Couldn't resolve this one? 1509 continue; 1510 } 1511 // Only mark those currently unmarked 1512 if (!nx->used) 1513 { 1514 nx->used = 1; 1515 newly_referenced_nodes.insert(nx); 1516 } 1517 } 1518 } 1519 } 1520 }; 1521 1522 // Seed our referenced nodes with those that have been seen by a node that 1523 // either will not be omitted if it's unreferenced or has a symbol. 1524 // Nodes with symbols are explicitly not garbage collected because they may 1525 // be expected for referencing by an overlay, and we do not want surprises 1526 // there. 1527 root->visit([&](node &n, node *) { 1528 if (!n.omit_if_no_ref || (write_symbols && !n.labels.empty())) 1529 { 1530 mark_referenced_nodes_used(n); 1531 } 1532 // Recurse as normal 1533 return node::VISIT_RECURSE; 1534 }, nullptr); 1535 1536 while (!newly_referenced_nodes.empty()) 1537 { 1538 previously_referenced_nodes = std::move(newly_referenced_nodes); 1539 for (auto *n : previously_referenced_nodes) 1540 { 1541 mark_referenced_nodes_used(*n); 1542 } 1543 } 1544 1545 previously_referenced_nodes.clear(); 1546 bool children_deleted = false; 1547 1548 // Delete 1549 root->visit([&](node &n, node *) { 1550 bool gc_children = false; 1551 1552 for (auto &cn : n.child_nodes()) 1553 { 1554 if (cn->omit_if_no_ref && !cn->used) 1555 { 1556 gc_children = true; 1557 break; 1558 } 1559 } 1560 1561 if (gc_children) 1562 { 1563 children_deleted = true; 1564 n.delete_children_if([](node_ptr &nx) { 1565 return (nx->omit_if_no_ref && !nx->used); 1566 }); 1567 1568 return node::VISIT_CONTINUE; 1569 } 1570 1571 return node::VISIT_RECURSE; 1572 }, nullptr); 1573 1574 return children_deleted; 1575 } 1576 1577 void 1578 device_tree::parse_file(text_input_buffer &input, 1579 std::vector<node_ptr> &roots, 1580 bool &read_header) 1581 { 1582 input.next_token(); 1583 // Read the header 1584 while (input.consume("/dts-v1/;")) 1585 { 1586 read_header = true; 1587 input.next_token(); 1588 } 1589 if (input.consume("/plugin/;")) 1590 { 1591 is_plugin = true; 1592 } 1593 input.next_token(); 1594 if (!read_header) 1595 { 1596 input.parse_error("Expected /dts-v1/; version string"); 1597 } 1598 // Read any memory reservations 1599 while (input.consume("/memreserve/")) 1600 { 1601 unsigned long long start, len; 1602 input.next_token(); 1603 // Read the start and length. 1604 if (!(input.consume_integer_expression(start) && 1605 (input.next_token(), 1606 input.consume_integer_expression(len)))) 1607 { 1608 input.parse_error("Expected size on /memreserve/ node."); 1609 } 1610 else 1611 { 1612 reservations.push_back(reservation(start, len)); 1613 } 1614 input.next_token(); 1615 input.consume(';'); 1616 input.next_token(); 1617 } 1618 while (valid && !input.finished()) 1619 { 1620 node_ptr n; 1621 if (input.consume('/')) 1622 { 1623 input.next_token(); 1624 n = node::parse(input, *this, string(), string_set(), string(), &defines); 1625 } 1626 else if (input.consume('&')) 1627 { 1628 input.next_token(); 1629 string name; 1630 bool name_is_path_reference = false; 1631 // This is to deal with names intended as path references, e.g. &{/path}. 1632 // While it may make sense in a non-plugin context, we don't support such 1633 // usage at this time. 1634 if (input.consume('{') && is_plugin) 1635 { 1636 name = input.parse_to('}'); 1637 input.consume('}'); 1638 name_is_path_reference = true; 1639 } 1640 else 1641 { 1642 name = input.parse_node_name(); 1643 } 1644 input.next_token(); 1645 n = node::parse(input, *this, std::move(name), string_set(), string(), &defines); 1646 if (n) 1647 { 1648 n->name_is_path_reference = name_is_path_reference; 1649 } 1650 } 1651 else 1652 { 1653 input.parse_error("Failed to find root node /."); 1654 } 1655 if (n) 1656 { 1657 roots.push_back(std::move(n)); 1658 } 1659 else 1660 { 1661 valid = false; 1662 } 1663 input.next_token(); 1664 } 1665 } 1666 1667 template<class writer> void 1668 device_tree::write(int fd) 1669 { 1670 dtb::string_table st; 1671 dtb::header head; 1672 writer head_writer; 1673 writer reservation_writer; 1674 writer struct_writer; 1675 writer strings_writer; 1676 1677 // Build the reservation table 1678 reservation_writer.write_comment(string("Memory reservations")); 1679 reservation_writer.write_label(string("dt_reserve_map")); 1680 for (auto &i : reservations) 1681 { 1682 reservation_writer.write_comment(string("Reservation start")); 1683 reservation_writer.write_data(i.first); 1684 reservation_writer.write_comment(string("Reservation length")); 1685 reservation_writer.write_data(i.second); 1686 } 1687 // Write n spare reserve map entries, plus the trailing 0. 1688 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++) 1689 { 1690 reservation_writer.write_data((uint64_t)0); 1691 reservation_writer.write_data((uint64_t)0); 1692 } 1693 1694 1695 struct_writer.write_comment(string("Device tree")); 1696 struct_writer.write_label(string("dt_struct_start")); 1697 root->write(struct_writer, st); 1698 struct_writer.write_token(dtb::FDT_END); 1699 struct_writer.write_label(string("dt_struct_end")); 1700 1701 st.write(strings_writer); 1702 // Find the strings size before we stick padding on the end. 1703 // Note: We should possibly use a new writer for the padding. 1704 head.size_dt_strings = strings_writer.size(); 1705 1706 // Stick the padding in the strings writer, but after the 1707 // marker indicating that it's the end. 1708 // Note: We probably should add a padding call to the writer so 1709 // that the asm back end can write padding directives instead 1710 // of a load of 0 bytes. 1711 for (uint32_t i=0 ; i<blob_padding ; i++) 1712 { 1713 strings_writer.write_data((uint8_t)0); 1714 } 1715 head.totalsize = sizeof(head) + strings_writer.size() + 1716 struct_writer.size() + reservation_writer.size(); 1717 while (head.totalsize < minimum_blob_size) 1718 { 1719 head.totalsize++; 1720 strings_writer.write_data((uint8_t)0); 1721 } 1722 head.off_dt_struct = sizeof(head) + reservation_writer.size();; 1723 head.off_dt_strings = head.off_dt_struct + struct_writer.size(); 1724 head.off_mem_rsvmap = sizeof(head); 1725 head.boot_cpuid_phys = boot_cpu; 1726 head.size_dt_struct = struct_writer.size(); 1727 head.write(head_writer); 1728 1729 head_writer.write_to_file(fd); 1730 reservation_writer.write_to_file(fd); 1731 struct_writer.write_to_file(fd); 1732 strings_writer.write_label(string("dt_blob_end")); 1733 strings_writer.write_to_file(fd); 1734 } 1735 1736 node* 1737 device_tree::referenced_node(property_value &v) 1738 { 1739 if (v.is_phandle()) 1740 { 1741 return node_names[v.string_data]; 1742 } 1743 if (v.is_binary()) 1744 { 1745 return used_phandles[v.get_as_uint32()]; 1746 } 1747 return 0; 1748 } 1749 1750 void 1751 device_tree::write_binary(int fd) 1752 { 1753 write<dtb::binary_writer>(fd); 1754 } 1755 1756 void 1757 device_tree::write_asm(int fd) 1758 { 1759 write<dtb::asm_writer>(fd); 1760 } 1761 1762 void 1763 device_tree::write_dts(int fd) 1764 { 1765 FILE *file = fdopen(fd, "w"); 1766 fputs("/dts-v1/;\n\n", file); 1767 1768 if (!reservations.empty()) 1769 { 1770 const char msg[] = "/memreserve/"; 1771 // Exclude the null byte when we're writing it out to the file. 1772 fwrite(msg, sizeof(msg) - 1, 1, file); 1773 for (auto &i : reservations) 1774 { 1775 fprintf(file, " 0x%" PRIx64 " 0x%" PRIx64, i.first, i.second); 1776 } 1777 fputs(";\n\n", file); 1778 } 1779 putc('/', file); 1780 putc(' ', file); 1781 root->write_dts(file, 0); 1782 fclose(file); 1783 } 1784 1785 void 1786 device_tree::parse_dtb(const string &fn, FILE *) 1787 { 1788 auto in = input_buffer::buffer_for_file(fn); 1789 if (in == 0) 1790 { 1791 valid = false; 1792 return; 1793 } 1794 input_buffer &input = *in; 1795 dtb::header h; 1796 valid = h.read_dtb(input); 1797 boot_cpu = h.boot_cpuid_phys; 1798 if (h.last_comp_version > 17) 1799 { 1800 fprintf(stderr, "Don't know how to read this version of the device tree blob"); 1801 valid = false; 1802 } 1803 if (!valid) 1804 { 1805 return; 1806 } 1807 input_buffer reservation_map = 1808 input.buffer_from_offset(h.off_mem_rsvmap, 0); 1809 uint64_t start, length; 1810 do 1811 { 1812 if (!(reservation_map.consume_binary(start) && 1813 reservation_map.consume_binary(length))) 1814 { 1815 fprintf(stderr, "Failed to read memory reservation table\n"); 1816 valid = false; 1817 return; 1818 } 1819 if (start != 0 || length != 0) 1820 { 1821 reservations.push_back(reservation(start, length)); 1822 } 1823 } while (!((start == 0) && (length == 0))); 1824 input_buffer struct_table = 1825 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct); 1826 input_buffer strings_table = 1827 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings); 1828 uint32_t token; 1829 if (!(struct_table.consume_binary(token) && 1830 (token == dtb::FDT_BEGIN_NODE))) 1831 { 1832 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n"); 1833 valid = false; 1834 return; 1835 } 1836 root = node::parse_dtb(struct_table, strings_table); 1837 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END))) 1838 { 1839 fprintf(stderr, "Expected FDT_END token after parsing root node.\n"); 1840 valid = false; 1841 return; 1842 } 1843 valid = (root != 0); 1844 } 1845 1846 string 1847 device_tree::node_path::to_string() const 1848 { 1849 string path; 1850 auto p = begin(); 1851 auto pe = end(); 1852 if ((p == pe) || (p+1 == pe)) 1853 { 1854 return string("/"); 1855 } 1856 // Skip the first name in the path. It's always "", and implicitly / 1857 for (++p ; p!=pe ; ++p) 1858 { 1859 path += '/'; 1860 path += p->first; 1861 if (!(p->second.empty())) 1862 { 1863 path += '@'; 1864 path += p->second; 1865 } 1866 } 1867 return path; 1868 } 1869 1870 node_ptr 1871 device_tree::create_fragment_wrapper(node_ptr &node, int &fragnum) 1872 { 1873 // In a plugin, we can massage these non-/ root nodes into into a fragment 1874 std::string fragment_address = "fragment@" + std::to_string(fragnum); 1875 ++fragnum; 1876 1877 std::vector<property_ptr> symbols; 1878 1879 // Intentionally left empty 1880 node_ptr newroot = node::create_special_node("", symbols); 1881 node_ptr wrapper = node::create_special_node("__overlay__", symbols); 1882 1883 // Generate the fragment with $propname = <&name> 1884 property_value v; 1885 std::string propname; 1886 v.string_data = node->name; 1887 if (!node->name_is_path_reference) 1888 { 1889 propname = "target"; 1890 v.type = property_value::PHANDLE; 1891 } 1892 else 1893 { 1894 propname = "target-path"; 1895 v.type = property_value::STRING; 1896 } 1897 auto prop = std::make_shared<property>(std::string(propname)); 1898 prop->add_value(v); 1899 symbols.push_back(prop); 1900 1901 node_ptr fragment = node::create_special_node(fragment_address, symbols); 1902 1903 wrapper->merge_node(node); 1904 fragment->add_child(std::move(wrapper)); 1905 newroot->add_child(std::move(fragment)); 1906 return newroot; 1907 } 1908 1909 node_ptr 1910 device_tree::generate_root(node_ptr &node, int &fragnum) 1911 { 1912 1913 string name = node->name; 1914 if (name == string()) 1915 { 1916 return std::move(node); 1917 } 1918 else if (!is_plugin) 1919 { 1920 return nullptr; 1921 } 1922 1923 return create_fragment_wrapper(node, fragnum); 1924 } 1925 1926 void 1927 device_tree::reassign_fragment_numbers(node_ptr &node, int &delta) 1928 { 1929 1930 for (auto &c : node->child_nodes()) 1931 { 1932 if (c->name == std::string("fragment")) 1933 { 1934 int current_address = std::stoi(c->unit_address, nullptr, 16); 1935 std::ostringstream new_address; 1936 current_address += delta; 1937 // It's possible that we hopped more than one somewhere, so just reset 1938 // delta to the next in sequence. 1939 delta = current_address + 1; 1940 new_address << std::hex << current_address; 1941 c->unit_address = new_address.str(); 1942 } 1943 } 1944 } 1945 1946 void 1947 device_tree::parse_dts(const string &fn, FILE *depfile) 1948 { 1949 auto in = input_buffer::buffer_for_file(fn); 1950 if (!in) 1951 { 1952 valid = false; 1953 return; 1954 } 1955 std::vector<node_ptr> roots; 1956 std::unordered_set<string> defnames; 1957 for (auto &i : defines) 1958 { 1959 defnames.insert(i.first); 1960 } 1961 text_input_buffer input(std::move(in), 1962 std::move(defnames), 1963 std::vector<string>(include_paths), 1964 dirname(fn), 1965 depfile); 1966 bool read_header = false; 1967 int fragnum = 0; 1968 parse_file(input, roots, read_header); 1969 switch (roots.size()) 1970 { 1971 case 0: 1972 valid = false; 1973 input.parse_error("Failed to find root node /."); 1974 return; 1975 case 1: 1976 root = generate_root(roots[0], fragnum); 1977 if (!root) 1978 { 1979 valid = false; 1980 input.parse_error("Failed to find root node /."); 1981 return; 1982 } 1983 break; 1984 default: 1985 { 1986 root = generate_root(roots[0], fragnum); 1987 if (!root) 1988 { 1989 valid = false; 1990 input.parse_error("Failed to find root node /."); 1991 return; 1992 } 1993 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i) 1994 { 1995 auto &node = *i; 1996 string name = node->name; 1997 if (name == string()) 1998 { 1999 if (is_plugin) 2000 { 2001 // Re-assign any fragment numbers based on a delta of 2002 // fragnum before we merge it 2003 reassign_fragment_numbers(node, fragnum); 2004 } 2005 root->merge_node(node); 2006 } 2007 else 2008 { 2009 auto existing = node_names.find(name); 2010 if (existing == node_names.end()) 2011 { 2012 collect_names(); 2013 existing = node_names.find(name); 2014 } 2015 if (existing == node_names.end()) 2016 { 2017 if (is_plugin) 2018 { 2019 auto fragment = create_fragment_wrapper(node, fragnum); 2020 root->merge_node(fragment); 2021 } 2022 else 2023 { 2024 fprintf(stderr, "Unable to merge node: %s\n", name.c_str()); 2025 } 2026 } 2027 else 2028 { 2029 existing->second->merge_node(node); 2030 } 2031 } 2032 } 2033 } 2034 } 2035 collect_names(); 2036 // Return value indicates whether we've dirtied the tree or not and need to 2037 // recollect names 2038 if (garbage_collect && garbage_collect_marked_nodes()) 2039 { 2040 collect_names(); 2041 } 2042 uint32_t phandle = 1; 2043 // If we're writing symbols, go ahead and assign phandles to the entire 2044 // tree. We'll do this before we resolve cross references, just to keep 2045 // order semi-predictable and stable. 2046 if (write_symbols) 2047 { 2048 assign_phandles(root, phandle); 2049 } 2050 resolve_cross_references(phandle); 2051 if (write_symbols) 2052 { 2053 std::vector<property_ptr> symbols; 2054 // Create a symbol table. Each label in this device tree may be 2055 // referenced by other plugins, so we create a __symbols__ node inside 2056 // the root that contains mappings (properties) from label names to 2057 // paths. 2058 for (auto i=ordered_node_paths.rbegin(), e=ordered_node_paths.rend() ; i!=e ; ++i) 2059 { 2060 auto &s = *i; 2061 if (node_paths.find(s.first) == node_paths.end()) 2062 { 2063 // Erased node, skip it. 2064 continue; 2065 } 2066 property_value v; 2067 v.string_data = s.second.to_string(); 2068 v.type = property_value::STRING; 2069 string name = s.first; 2070 auto prop = std::make_shared<property>(std::move(name)); 2071 prop->add_value(v); 2072 symbols.push_back(prop); 2073 } 2074 root->add_child(node::create_special_node("__symbols__", symbols)); 2075 } 2076 // If this is a plugin, then we also need to create two extra nodes. 2077 // Internal phandles will need to be renumbered to avoid conflicts with 2078 // already-loaded nodes and external references will need to be 2079 // resolved. 2080 if (is_plugin) 2081 { 2082 std::vector<property_ptr> symbols; 2083 // Create the fixups entry. This is of the form: 2084 // {target} = {path}:{property name}:{offset} 2085 auto create_fixup_entry = [&](fixup &i, string target) 2086 { 2087 string value = i.path.to_string(); 2088 value += ':'; 2089 value += i.prop->get_key(); 2090 value += ':'; 2091 value += std::to_string(i.prop->offset_of_value(i.val)); 2092 property_value v; 2093 v.string_data = value; 2094 v.type = property_value::STRING; 2095 auto prop = std::make_shared<property>(std::move(target)); 2096 prop->add_value(v); 2097 return prop; 2098 }; 2099 // If we have any unresolved phandle references in this plugin, 2100 // then we must update them to 0xdeadbeef and leave a property in 2101 // the /__fixups__ node whose key is the label and whose value is 2102 // as described above. 2103 if (!unresolved_fixups.empty()) 2104 { 2105 for (auto &i : unresolved_fixups) 2106 { 2107 auto &val = i.get().val; 2108 symbols.push_back(create_fixup_entry(i, val.string_data)); 2109 val.byte_data.push_back(0xde); 2110 val.byte_data.push_back(0xad); 2111 val.byte_data.push_back(0xbe); 2112 val.byte_data.push_back(0xef); 2113 val.type = property_value::BINARY; 2114 } 2115 root->add_child(node::create_special_node("__fixups__", symbols)); 2116 } 2117 symbols.clear(); 2118 // If we have any resolved phandle references in this plugin, then 2119 // we must create a child in the __local_fixups__ node whose path 2120 // matches the node path from the root and whose value contains the 2121 // location of the reference within a property. 2122 2123 // Create a local_fixups node that is initially empty. 2124 node_ptr local_fixups = node::create_special_node("__local_fixups__", symbols); 2125 for (auto &i : fixups) 2126 { 2127 if (!i.val.is_phandle()) 2128 { 2129 continue; 2130 } 2131 node *n = local_fixups.get(); 2132 for (auto &p : i.path) 2133 { 2134 // Skip the implicit root 2135 if (p.first.empty()) 2136 { 2137 continue; 2138 } 2139 bool found = false; 2140 for (auto &c : n->child_nodes()) 2141 { 2142 if (c->name == p.first) 2143 { 2144 if (c->unit_address == p.second) 2145 { 2146 n = c.get(); 2147 found = true; 2148 break; 2149 } 2150 } 2151 } 2152 if (!found) 2153 { 2154 string path = p.first; 2155 if (!(p.second.empty())) 2156 { 2157 path += '@'; 2158 path += p.second; 2159 } 2160 n->add_child(node::create_special_node(path, symbols)); 2161 n = (--n->child_end())->get(); 2162 } 2163 } 2164 assert(n); 2165 property_value pv; 2166 push_big_endian(pv.byte_data, static_cast<uint32_t>(i.prop->offset_of_value(i.val))); 2167 pv.type = property_value::BINARY; 2168 auto key = i.prop->get_key(); 2169 property_ptr prop = n->get_property(key); 2170 // If we don't have an existing property then create one and 2171 // use this property value 2172 if (!prop) 2173 { 2174 prop = std::make_shared<property>(std::move(key)); 2175 n->add_property(prop); 2176 prop->add_value(pv); 2177 } 2178 else 2179 { 2180 // If we do have an existing property value, try to append 2181 // this value. 2182 property_value &old_val = *(--prop->end()); 2183 if (!old_val.try_to_merge(pv)) 2184 { 2185 prop->add_value(pv); 2186 } 2187 } 2188 } 2189 // We've iterated over all fixups, but only emit the 2190 // __local_fixups__ if we found some that were resolved internally. 2191 if (local_fixups->child_begin() != local_fixups->child_end()) 2192 { 2193 root->add_child(std::move(local_fixups)); 2194 } 2195 } 2196 } 2197 2198 bool device_tree::parse_define(const char *def) 2199 { 2200 const char *val = strchr(def, '='); 2201 if (!val) 2202 { 2203 if (strlen(def) != 0) 2204 { 2205 string name(def); 2206 defines[name]; 2207 return true; 2208 } 2209 return false; 2210 } 2211 string name(def, val-def); 2212 string name_copy = name; 2213 val++; 2214 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val))); 2215 text_input_buffer in(std::move(raw), 2216 std::unordered_set<string>(), 2217 std::vector<string>(), 2218 string(), 2219 nullptr); 2220 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false); 2221 if (p) 2222 defines[name] = p; 2223 return (bool)p; 2224 } 2225 2226 } // namespace fdt 2227 2228 } // namespace dtc 2229 2230