1 /* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21 #include "dtc.h" 22 23 /* 24 * Tree building functions 25 */ 26 27 void add_label(struct label **labels, char *label) 28 { 29 struct label *new; 30 31 /* Make sure the label isn't already there */ 32 for_each_label_withdel(*labels, new) 33 if (streq(new->label, label)) { 34 new->deleted = 0; 35 return; 36 } 37 38 new = xmalloc(sizeof(*new)); 39 memset(new, 0, sizeof(*new)); 40 new->label = label; 41 new->next = *labels; 42 *labels = new; 43 } 44 45 void delete_labels(struct label **labels) 46 { 47 struct label *label; 48 49 for_each_label(*labels, label) 50 label->deleted = 1; 51 } 52 53 struct property *build_property(char *name, struct data val) 54 { 55 struct property *new = xmalloc(sizeof(*new)); 56 57 memset(new, 0, sizeof(*new)); 58 59 new->name = name; 60 new->val = val; 61 62 return new; 63 } 64 65 struct property *build_property_delete(char *name) 66 { 67 struct property *new = xmalloc(sizeof(*new)); 68 69 memset(new, 0, sizeof(*new)); 70 71 new->name = name; 72 new->deleted = 1; 73 74 return new; 75 } 76 77 struct property *chain_property(struct property *first, struct property *list) 78 { 79 assert(first->next == NULL); 80 81 first->next = list; 82 return first; 83 } 84 85 struct property *reverse_properties(struct property *first) 86 { 87 struct property *p = first; 88 struct property *head = NULL; 89 struct property *next; 90 91 while (p) { 92 next = p->next; 93 p->next = head; 94 head = p; 95 p = next; 96 } 97 return head; 98 } 99 100 struct node *build_node(struct property *proplist, struct node *children) 101 { 102 struct node *new = xmalloc(sizeof(*new)); 103 struct node *child; 104 105 memset(new, 0, sizeof(*new)); 106 107 new->proplist = reverse_properties(proplist); 108 new->children = children; 109 110 for_each_child(new, child) { 111 child->parent = new; 112 } 113 114 return new; 115 } 116 117 struct node *build_node_delete(void) 118 { 119 struct node *new = xmalloc(sizeof(*new)); 120 121 memset(new, 0, sizeof(*new)); 122 123 new->deleted = 1; 124 125 return new; 126 } 127 128 struct node *name_node(struct node *node, char *name) 129 { 130 assert(node->name == NULL); 131 132 node->name = name; 133 134 return node; 135 } 136 137 struct node *merge_nodes(struct node *old_node, struct node *new_node) 138 { 139 struct property *new_prop, *old_prop; 140 struct node *new_child, *old_child; 141 struct label *l; 142 143 old_node->deleted = 0; 144 145 /* Add new node labels to old node */ 146 for_each_label_withdel(new_node->labels, l) 147 add_label(&old_node->labels, l->label); 148 149 /* Move properties from the new node to the old node. If there 150 * is a collision, replace the old value with the new */ 151 while (new_node->proplist) { 152 /* Pop the property off the list */ 153 new_prop = new_node->proplist; 154 new_node->proplist = new_prop->next; 155 new_prop->next = NULL; 156 157 if (new_prop->deleted) { 158 delete_property_by_name(old_node, new_prop->name); 159 free(new_prop); 160 continue; 161 } 162 163 /* Look for a collision, set new value if there is */ 164 for_each_property_withdel(old_node, old_prop) { 165 if (streq(old_prop->name, new_prop->name)) { 166 /* Add new labels to old property */ 167 for_each_label_withdel(new_prop->labels, l) 168 add_label(&old_prop->labels, l->label); 169 170 old_prop->val = new_prop->val; 171 old_prop->deleted = 0; 172 free(new_prop); 173 new_prop = NULL; 174 break; 175 } 176 } 177 178 /* if no collision occurred, add property to the old node. */ 179 if (new_prop) 180 add_property(old_node, new_prop); 181 } 182 183 /* Move the override child nodes into the primary node. If 184 * there is a collision, then merge the nodes. */ 185 while (new_node->children) { 186 /* Pop the child node off the list */ 187 new_child = new_node->children; 188 new_node->children = new_child->next_sibling; 189 new_child->parent = NULL; 190 new_child->next_sibling = NULL; 191 192 if (new_child->deleted) { 193 delete_node_by_name(old_node, new_child->name); 194 free(new_child); 195 continue; 196 } 197 198 /* Search for a collision. Merge if there is */ 199 for_each_child_withdel(old_node, old_child) { 200 if (streq(old_child->name, new_child->name)) { 201 merge_nodes(old_child, new_child); 202 new_child = NULL; 203 break; 204 } 205 } 206 207 /* if no collision occurred, add child to the old node. */ 208 if (new_child) 209 add_child(old_node, new_child); 210 } 211 212 /* The new node contents are now merged into the old node. Free 213 * the new node. */ 214 free(new_node); 215 216 return old_node; 217 } 218 219 void add_orphan_node(struct node *dt, struct node *new_node, char *ref) 220 { 221 static unsigned int next_orphan_fragment = 0; 222 struct node *node; 223 struct property *p; 224 struct data d = empty_data; 225 char *name; 226 227 d = data_add_marker(d, REF_PHANDLE, ref); 228 d = data_append_integer(d, 0xffffffff, 32); 229 230 p = build_property("target", d); 231 232 xasprintf(&name, "fragment@%u", 233 next_orphan_fragment++); 234 name_node(new_node, "__overlay__"); 235 node = build_node(p, new_node); 236 name_node(node, name); 237 238 add_child(dt, node); 239 } 240 241 struct node *chain_node(struct node *first, struct node *list) 242 { 243 assert(first->next_sibling == NULL); 244 245 first->next_sibling = list; 246 return first; 247 } 248 249 void add_property(struct node *node, struct property *prop) 250 { 251 struct property **p; 252 253 prop->next = NULL; 254 255 p = &node->proplist; 256 while (*p) 257 p = &((*p)->next); 258 259 *p = prop; 260 } 261 262 void delete_property_by_name(struct node *node, char *name) 263 { 264 struct property *prop = node->proplist; 265 266 while (prop) { 267 if (streq(prop->name, name)) { 268 delete_property(prop); 269 return; 270 } 271 prop = prop->next; 272 } 273 } 274 275 void delete_property(struct property *prop) 276 { 277 prop->deleted = 1; 278 delete_labels(&prop->labels); 279 } 280 281 void add_child(struct node *parent, struct node *child) 282 { 283 struct node **p; 284 285 child->next_sibling = NULL; 286 child->parent = parent; 287 288 p = &parent->children; 289 while (*p) 290 p = &((*p)->next_sibling); 291 292 *p = child; 293 } 294 295 void delete_node_by_name(struct node *parent, char *name) 296 { 297 struct node *node = parent->children; 298 299 while (node) { 300 if (streq(node->name, name)) { 301 delete_node(node); 302 return; 303 } 304 node = node->next_sibling; 305 } 306 } 307 308 void delete_node(struct node *node) 309 { 310 struct property *prop; 311 struct node *child; 312 313 node->deleted = 1; 314 for_each_child(node, child) 315 delete_node(child); 316 for_each_property(node, prop) 317 delete_property(prop); 318 delete_labels(&node->labels); 319 } 320 321 void append_to_property(struct node *node, 322 char *name, const void *data, int len) 323 { 324 struct data d; 325 struct property *p; 326 327 p = get_property(node, name); 328 if (p) { 329 d = data_append_data(p->val, data, len); 330 p->val = d; 331 } else { 332 d = data_append_data(empty_data, data, len); 333 p = build_property(name, d); 334 add_property(node, p); 335 } 336 } 337 338 struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) 339 { 340 struct reserve_info *new = xmalloc(sizeof(*new)); 341 342 memset(new, 0, sizeof(*new)); 343 344 new->address = address; 345 new->size = size; 346 347 return new; 348 } 349 350 struct reserve_info *chain_reserve_entry(struct reserve_info *first, 351 struct reserve_info *list) 352 { 353 assert(first->next == NULL); 354 355 first->next = list; 356 return first; 357 } 358 359 struct reserve_info *add_reserve_entry(struct reserve_info *list, 360 struct reserve_info *new) 361 { 362 struct reserve_info *last; 363 364 new->next = NULL; 365 366 if (! list) 367 return new; 368 369 for (last = list; last->next; last = last->next) 370 ; 371 372 last->next = new; 373 374 return list; 375 } 376 377 struct dt_info *build_dt_info(unsigned int dtsflags, 378 struct reserve_info *reservelist, 379 struct node *tree, uint32_t boot_cpuid_phys) 380 { 381 struct dt_info *dti; 382 383 dti = xmalloc(sizeof(*dti)); 384 dti->dtsflags = dtsflags; 385 dti->reservelist = reservelist; 386 dti->dt = tree; 387 dti->boot_cpuid_phys = boot_cpuid_phys; 388 389 return dti; 390 } 391 392 /* 393 * Tree accessor functions 394 */ 395 396 const char *get_unitname(struct node *node) 397 { 398 if (node->name[node->basenamelen] == '\0') 399 return ""; 400 else 401 return node->name + node->basenamelen + 1; 402 } 403 404 struct property *get_property(struct node *node, const char *propname) 405 { 406 struct property *prop; 407 408 for_each_property(node, prop) 409 if (streq(prop->name, propname)) 410 return prop; 411 412 return NULL; 413 } 414 415 cell_t propval_cell(struct property *prop) 416 { 417 assert(prop->val.len == sizeof(cell_t)); 418 return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); 419 } 420 421 cell_t propval_cell_n(struct property *prop, int n) 422 { 423 assert(prop->val.len / sizeof(cell_t) >= n); 424 return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); 425 } 426 427 struct property *get_property_by_label(struct node *tree, const char *label, 428 struct node **node) 429 { 430 struct property *prop; 431 struct node *c; 432 433 *node = tree; 434 435 for_each_property(tree, prop) { 436 struct label *l; 437 438 for_each_label(prop->labels, l) 439 if (streq(l->label, label)) 440 return prop; 441 } 442 443 for_each_child(tree, c) { 444 prop = get_property_by_label(c, label, node); 445 if (prop) 446 return prop; 447 } 448 449 *node = NULL; 450 return NULL; 451 } 452 453 struct marker *get_marker_label(struct node *tree, const char *label, 454 struct node **node, struct property **prop) 455 { 456 struct marker *m; 457 struct property *p; 458 struct node *c; 459 460 *node = tree; 461 462 for_each_property(tree, p) { 463 *prop = p; 464 m = p->val.markers; 465 for_each_marker_of_type(m, LABEL) 466 if (streq(m->ref, label)) 467 return m; 468 } 469 470 for_each_child(tree, c) { 471 m = get_marker_label(c, label, node, prop); 472 if (m) 473 return m; 474 } 475 476 *prop = NULL; 477 *node = NULL; 478 return NULL; 479 } 480 481 struct node *get_subnode(struct node *node, const char *nodename) 482 { 483 struct node *child; 484 485 for_each_child(node, child) 486 if (streq(child->name, nodename)) 487 return child; 488 489 return NULL; 490 } 491 492 struct node *get_node_by_path(struct node *tree, const char *path) 493 { 494 const char *p; 495 struct node *child; 496 497 if (!path || ! (*path)) { 498 if (tree->deleted) 499 return NULL; 500 return tree; 501 } 502 503 while (path[0] == '/') 504 path++; 505 506 p = strchr(path, '/'); 507 508 for_each_child(tree, child) { 509 if (p && (strlen(child->name) == p-path) && 510 strneq(path, child->name, p-path)) 511 return get_node_by_path(child, p+1); 512 else if (!p && streq(path, child->name)) 513 return child; 514 } 515 516 return NULL; 517 } 518 519 struct node *get_node_by_label(struct node *tree, const char *label) 520 { 521 struct node *child, *node; 522 struct label *l; 523 524 assert(label && (strlen(label) > 0)); 525 526 for_each_label(tree->labels, l) 527 if (streq(l->label, label)) 528 return tree; 529 530 for_each_child(tree, child) { 531 node = get_node_by_label(child, label); 532 if (node) 533 return node; 534 } 535 536 return NULL; 537 } 538 539 struct node *get_node_by_phandle(struct node *tree, cell_t phandle) 540 { 541 struct node *child, *node; 542 543 assert((phandle != 0) && (phandle != -1)); 544 545 if (tree->phandle == phandle) { 546 if (tree->deleted) 547 return NULL; 548 return tree; 549 } 550 551 for_each_child(tree, child) { 552 node = get_node_by_phandle(child, phandle); 553 if (node) 554 return node; 555 } 556 557 return NULL; 558 } 559 560 struct node *get_node_by_ref(struct node *tree, const char *ref) 561 { 562 if (streq(ref, "/")) 563 return tree; 564 else if (ref[0] == '/') 565 return get_node_by_path(tree, ref); 566 else 567 return get_node_by_label(tree, ref); 568 } 569 570 cell_t get_node_phandle(struct node *root, struct node *node) 571 { 572 static cell_t phandle = 1; /* FIXME: ick, static local */ 573 574 if ((node->phandle != 0) && (node->phandle != -1)) 575 return node->phandle; 576 577 while (get_node_by_phandle(root, phandle)) 578 phandle++; 579 580 node->phandle = phandle; 581 582 if (!get_property(node, "linux,phandle") 583 && (phandle_format & PHANDLE_LEGACY)) 584 add_property(node, 585 build_property("linux,phandle", 586 data_append_cell(empty_data, phandle))); 587 588 if (!get_property(node, "phandle") 589 && (phandle_format & PHANDLE_EPAPR)) 590 add_property(node, 591 build_property("phandle", 592 data_append_cell(empty_data, phandle))); 593 594 /* If the node *does* have a phandle property, we must 595 * be dealing with a self-referencing phandle, which will be 596 * fixed up momentarily in the caller */ 597 598 return node->phandle; 599 } 600 601 uint32_t guess_boot_cpuid(struct node *tree) 602 { 603 struct node *cpus, *bootcpu; 604 struct property *reg; 605 606 cpus = get_node_by_path(tree, "/cpus"); 607 if (!cpus) 608 return 0; 609 610 611 bootcpu = cpus->children; 612 if (!bootcpu) 613 return 0; 614 615 reg = get_property(bootcpu, "reg"); 616 if (!reg || (reg->val.len != sizeof(uint32_t))) 617 return 0; 618 619 /* FIXME: Sanity check node? */ 620 621 return propval_cell(reg); 622 } 623 624 static int cmp_reserve_info(const void *ax, const void *bx) 625 { 626 const struct reserve_info *a, *b; 627 628 a = *((const struct reserve_info * const *)ax); 629 b = *((const struct reserve_info * const *)bx); 630 631 if (a->address < b->address) 632 return -1; 633 else if (a->address > b->address) 634 return 1; 635 else if (a->size < b->size) 636 return -1; 637 else if (a->size > b->size) 638 return 1; 639 else 640 return 0; 641 } 642 643 static void sort_reserve_entries(struct dt_info *dti) 644 { 645 struct reserve_info *ri, **tbl; 646 int n = 0, i = 0; 647 648 for (ri = dti->reservelist; 649 ri; 650 ri = ri->next) 651 n++; 652 653 if (n == 0) 654 return; 655 656 tbl = xmalloc(n * sizeof(*tbl)); 657 658 for (ri = dti->reservelist; 659 ri; 660 ri = ri->next) 661 tbl[i++] = ri; 662 663 qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); 664 665 dti->reservelist = tbl[0]; 666 for (i = 0; i < (n-1); i++) 667 tbl[i]->next = tbl[i+1]; 668 tbl[n-1]->next = NULL; 669 670 free(tbl); 671 } 672 673 static int cmp_prop(const void *ax, const void *bx) 674 { 675 const struct property *a, *b; 676 677 a = *((const struct property * const *)ax); 678 b = *((const struct property * const *)bx); 679 680 return strcmp(a->name, b->name); 681 } 682 683 static void sort_properties(struct node *node) 684 { 685 int n = 0, i = 0; 686 struct property *prop, **tbl; 687 688 for_each_property_withdel(node, prop) 689 n++; 690 691 if (n == 0) 692 return; 693 694 tbl = xmalloc(n * sizeof(*tbl)); 695 696 for_each_property_withdel(node, prop) 697 tbl[i++] = prop; 698 699 qsort(tbl, n, sizeof(*tbl), cmp_prop); 700 701 node->proplist = tbl[0]; 702 for (i = 0; i < (n-1); i++) 703 tbl[i]->next = tbl[i+1]; 704 tbl[n-1]->next = NULL; 705 706 free(tbl); 707 } 708 709 static int cmp_subnode(const void *ax, const void *bx) 710 { 711 const struct node *a, *b; 712 713 a = *((const struct node * const *)ax); 714 b = *((const struct node * const *)bx); 715 716 return strcmp(a->name, b->name); 717 } 718 719 static void sort_subnodes(struct node *node) 720 { 721 int n = 0, i = 0; 722 struct node *subnode, **tbl; 723 724 for_each_child_withdel(node, subnode) 725 n++; 726 727 if (n == 0) 728 return; 729 730 tbl = xmalloc(n * sizeof(*tbl)); 731 732 for_each_child_withdel(node, subnode) 733 tbl[i++] = subnode; 734 735 qsort(tbl, n, sizeof(*tbl), cmp_subnode); 736 737 node->children = tbl[0]; 738 for (i = 0; i < (n-1); i++) 739 tbl[i]->next_sibling = tbl[i+1]; 740 tbl[n-1]->next_sibling = NULL; 741 742 free(tbl); 743 } 744 745 static void sort_node(struct node *node) 746 { 747 struct node *c; 748 749 sort_properties(node); 750 sort_subnodes(node); 751 for_each_child_withdel(node, c) 752 sort_node(c); 753 } 754 755 void sort_tree(struct dt_info *dti) 756 { 757 sort_reserve_entries(dti); 758 sort_node(dti->dt); 759 } 760 761 /* utility helper to avoid code duplication */ 762 static struct node *build_and_name_child_node(struct node *parent, char *name) 763 { 764 struct node *node; 765 766 node = build_node(NULL, NULL); 767 name_node(node, xstrdup(name)); 768 add_child(parent, node); 769 770 return node; 771 } 772 773 static struct node *build_root_node(struct node *dt, char *name) 774 { 775 struct node *an; 776 777 an = get_subnode(dt, name); 778 if (!an) 779 an = build_and_name_child_node(dt, name); 780 781 if (!an) 782 die("Could not build root node /%s\n", name); 783 784 return an; 785 } 786 787 static bool any_label_tree(struct dt_info *dti, struct node *node) 788 { 789 struct node *c; 790 791 if (node->labels) 792 return true; 793 794 for_each_child(node, c) 795 if (any_label_tree(dti, c)) 796 return true; 797 798 return false; 799 } 800 801 static void generate_label_tree_internal(struct dt_info *dti, 802 struct node *an, struct node *node, 803 bool allocph) 804 { 805 struct node *dt = dti->dt; 806 struct node *c; 807 struct property *p; 808 struct label *l; 809 810 /* if there are labels */ 811 if (node->labels) { 812 813 /* now add the label in the node */ 814 for_each_label(node->labels, l) { 815 816 /* check whether the label already exists */ 817 p = get_property(an, l->label); 818 if (p) { 819 fprintf(stderr, "WARNING: label %s already" 820 " exists in /%s", l->label, 821 an->name); 822 continue; 823 } 824 825 /* insert it */ 826 p = build_property(l->label, 827 data_copy_mem(node->fullpath, 828 strlen(node->fullpath) + 1)); 829 add_property(an, p); 830 } 831 832 /* force allocation of a phandle for this node */ 833 if (allocph) 834 (void)get_node_phandle(dt, node); 835 } 836 837 for_each_child(node, c) 838 generate_label_tree_internal(dti, an, c, allocph); 839 } 840 841 static bool any_fixup_tree(struct dt_info *dti, struct node *node) 842 { 843 struct node *c; 844 struct property *prop; 845 struct marker *m; 846 847 for_each_property(node, prop) { 848 m = prop->val.markers; 849 for_each_marker_of_type(m, REF_PHANDLE) { 850 if (!get_node_by_ref(dti->dt, m->ref)) 851 return true; 852 } 853 } 854 855 for_each_child(node, c) { 856 if (any_fixup_tree(dti, c)) 857 return true; 858 } 859 860 return false; 861 } 862 863 static void add_fixup_entry(struct dt_info *dti, struct node *fn, 864 struct node *node, struct property *prop, 865 struct marker *m) 866 { 867 char *entry; 868 869 /* m->ref can only be a REF_PHANDLE, but check anyway */ 870 assert(m->type == REF_PHANDLE); 871 872 /* there shouldn't be any ':' in the arguments */ 873 if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) 874 die("arguments should not contain ':'\n"); 875 876 xasprintf(&entry, "%s:%s:%u", 877 node->fullpath, prop->name, m->offset); 878 append_to_property(fn, m->ref, entry, strlen(entry) + 1); 879 880 free(entry); 881 } 882 883 static void generate_fixups_tree_internal(struct dt_info *dti, 884 struct node *fn, 885 struct node *node) 886 { 887 struct node *dt = dti->dt; 888 struct node *c; 889 struct property *prop; 890 struct marker *m; 891 struct node *refnode; 892 893 for_each_property(node, prop) { 894 m = prop->val.markers; 895 for_each_marker_of_type(m, REF_PHANDLE) { 896 refnode = get_node_by_ref(dt, m->ref); 897 if (!refnode) 898 add_fixup_entry(dti, fn, node, prop, m); 899 } 900 } 901 902 for_each_child(node, c) 903 generate_fixups_tree_internal(dti, fn, c); 904 } 905 906 static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) 907 { 908 struct node *c; 909 struct property *prop; 910 struct marker *m; 911 912 for_each_property(node, prop) { 913 m = prop->val.markers; 914 for_each_marker_of_type(m, REF_PHANDLE) { 915 if (get_node_by_ref(dti->dt, m->ref)) 916 return true; 917 } 918 } 919 920 for_each_child(node, c) { 921 if (any_local_fixup_tree(dti, c)) 922 return true; 923 } 924 925 return false; 926 } 927 928 static void add_local_fixup_entry(struct dt_info *dti, 929 struct node *lfn, struct node *node, 930 struct property *prop, struct marker *m, 931 struct node *refnode) 932 { 933 struct node *wn, *nwn; /* local fixup node, walk node, new */ 934 fdt32_t value_32; 935 char **compp; 936 int i, depth; 937 938 /* walk back retreiving depth */ 939 depth = 0; 940 for (wn = node; wn; wn = wn->parent) 941 depth++; 942 943 /* allocate name array */ 944 compp = xmalloc(sizeof(*compp) * depth); 945 946 /* store names in the array */ 947 for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) 948 compp[i] = wn->name; 949 950 /* walk the path components creating nodes if they don't exist */ 951 for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { 952 /* if no node exists, create it */ 953 nwn = get_subnode(wn, compp[i]); 954 if (!nwn) 955 nwn = build_and_name_child_node(wn, compp[i]); 956 } 957 958 free(compp); 959 960 value_32 = cpu_to_fdt32(m->offset); 961 append_to_property(wn, prop->name, &value_32, sizeof(value_32)); 962 } 963 964 static void generate_local_fixups_tree_internal(struct dt_info *dti, 965 struct node *lfn, 966 struct node *node) 967 { 968 struct node *dt = dti->dt; 969 struct node *c; 970 struct property *prop; 971 struct marker *m; 972 struct node *refnode; 973 974 for_each_property(node, prop) { 975 m = prop->val.markers; 976 for_each_marker_of_type(m, REF_PHANDLE) { 977 refnode = get_node_by_ref(dt, m->ref); 978 if (refnode) 979 add_local_fixup_entry(dti, lfn, node, prop, m, refnode); 980 } 981 } 982 983 for_each_child(node, c) 984 generate_local_fixups_tree_internal(dti, lfn, c); 985 } 986 987 void generate_label_tree(struct dt_info *dti, char *name, bool allocph) 988 { 989 if (!any_label_tree(dti, dti->dt)) 990 return; 991 generate_label_tree_internal(dti, build_root_node(dti->dt, name), 992 dti->dt, allocph); 993 } 994 995 void generate_fixups_tree(struct dt_info *dti, char *name) 996 { 997 if (!any_fixup_tree(dti, dti->dt)) 998 return; 999 generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1000 dti->dt); 1001 } 1002 1003 void generate_local_fixups_tree(struct dt_info *dti, char *name) 1004 { 1005 if (!any_local_fixup_tree(dti, dti->dt)) 1006 return; 1007 generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1008 dti->dt); 1009 } 1010