1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 /* 3 * libfdt - Flat Device Tree manipulation 4 * Copyright (C) 2016 Free Electrons 5 * Copyright (C) 2016 NextThing Co. 6 */ 7 #include "libfdt_env.h" 8 9 #include <fdt.h> 10 #include <libfdt.h> 11 12 #include "libfdt_internal.h" 13 14 /** 15 * overlay_get_target_phandle - retrieves the target phandle of a fragment 16 * @fdto: pointer to the device tree overlay blob 17 * @fragment: node offset of the fragment in the overlay 18 * 19 * overlay_get_target_phandle() retrieves the target phandle of an 20 * overlay fragment when that fragment uses a phandle (target 21 * property) instead of a path (target-path property). 22 * 23 * returns: 24 * the phandle pointed by the target property 25 * 0, if the phandle was not found 26 * -1, if the phandle was malformed 27 */ 28 static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) 29 { 30 const fdt32_t *val; 31 int len; 32 33 val = fdt_getprop(fdto, fragment, "target", &len); 34 if (!val) 35 return 0; 36 37 if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) 38 return (uint32_t)-1; 39 40 return fdt32_to_cpu(*val); 41 } 42 43 /** 44 * overlay_get_target - retrieves the offset of a fragment's target 45 * @fdt: Base device tree blob 46 * @fdto: Device tree overlay blob 47 * @fragment: node offset of the fragment in the overlay 48 * @pathp: pointer which receives the path of the target (or NULL) 49 * 50 * overlay_get_target() retrieves the target offset in the base 51 * device tree of a fragment, no matter how the actual targeting is 52 * done (through a phandle or a path) 53 * 54 * returns: 55 * the targeted node offset in the base device tree 56 * Negative error code on error 57 */ 58 static int overlay_get_target(const void *fdt, const void *fdto, 59 int fragment, char const **pathp) 60 { 61 uint32_t phandle; 62 const char *path = NULL; 63 int path_len = 0, ret; 64 65 /* Try first to do a phandle based lookup */ 66 phandle = overlay_get_target_phandle(fdto, fragment); 67 if (phandle == (uint32_t)-1) 68 return -FDT_ERR_BADPHANDLE; 69 70 /* no phandle, try path */ 71 if (!phandle) { 72 /* And then a path based lookup */ 73 path = fdt_getprop(fdto, fragment, "target-path", &path_len); 74 if (path) 75 ret = fdt_path_offset(fdt, path); 76 else 77 ret = path_len; 78 } else 79 ret = fdt_node_offset_by_phandle(fdt, phandle); 80 81 /* 82 * If we haven't found either a target or a 83 * target-path property in a node that contains a 84 * __overlay__ subnode (we wouldn't be called 85 * otherwise), consider it a improperly written 86 * overlay 87 */ 88 if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) 89 ret = -FDT_ERR_BADOVERLAY; 90 91 /* return on error */ 92 if (ret < 0) 93 return ret; 94 95 /* return pointer to path (if available) */ 96 if (pathp) 97 *pathp = path ? path : NULL; 98 99 return ret; 100 } 101 102 /** 103 * overlay_phandle_add_offset - Increases a phandle by an offset 104 * @fdt: Base device tree blob 105 * @node: Device tree overlay blob 106 * @name: Name of the property to modify (phandle or linux,phandle) 107 * @delta: offset to apply 108 * 109 * overlay_phandle_add_offset() increments a node phandle by a given 110 * offset. 111 * 112 * returns: 113 * 0 on success. 114 * Negative error code on error 115 */ 116 static int overlay_phandle_add_offset(void *fdt, int node, 117 const char *name, uint32_t delta) 118 { 119 const fdt32_t *val; 120 uint32_t adj_val; 121 int len; 122 123 val = fdt_getprop(fdt, node, name, &len); 124 if (!val) 125 return len; 126 127 if (len != sizeof(*val)) 128 return -FDT_ERR_BADPHANDLE; 129 130 adj_val = fdt32_to_cpu(*val); 131 if ((adj_val + delta) < adj_val) 132 return -FDT_ERR_NOPHANDLES; 133 134 adj_val += delta; 135 if (adj_val == (uint32_t)-1) 136 return -FDT_ERR_NOPHANDLES; 137 138 return fdt_setprop_inplace_u32(fdt, node, name, adj_val); 139 } 140 141 /** 142 * overlay_adjust_node_phandles - Offsets the phandles of a node 143 * @fdto: Device tree overlay blob 144 * @node: Offset of the node we want to adjust 145 * @delta: Offset to shift the phandles of 146 * 147 * overlay_adjust_node_phandles() adds a constant to all the phandles 148 * of a given node. This is mainly use as part of the overlay 149 * application process, when we want to update all the overlay 150 * phandles to not conflict with the overlays of the base device tree. 151 * 152 * returns: 153 * 0 on success 154 * Negative error code on failure 155 */ 156 static int overlay_adjust_node_phandles(void *fdto, int node, 157 uint32_t delta) 158 { 159 int child; 160 int ret; 161 162 ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); 163 if (ret && ret != -FDT_ERR_NOTFOUND) 164 return ret; 165 166 ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); 167 if (ret && ret != -FDT_ERR_NOTFOUND) 168 return ret; 169 170 fdt_for_each_subnode(child, fdto, node) { 171 ret = overlay_adjust_node_phandles(fdto, child, delta); 172 if (ret) 173 return ret; 174 } 175 176 return 0; 177 } 178 179 /** 180 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay 181 * @fdto: Device tree overlay blob 182 * @delta: Offset to shift the phandles of 183 * 184 * overlay_adjust_local_phandles() adds a constant to all the 185 * phandles of an overlay. This is mainly use as part of the overlay 186 * application process, when we want to update all the overlay 187 * phandles to not conflict with the overlays of the base device tree. 188 * 189 * returns: 190 * 0 on success 191 * Negative error code on failure 192 */ 193 static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) 194 { 195 /* 196 * Start adjusting the phandles from the overlay root 197 */ 198 return overlay_adjust_node_phandles(fdto, 0, delta); 199 } 200 201 /** 202 * overlay_update_local_node_references - Adjust the overlay references 203 * @fdto: Device tree overlay blob 204 * @tree_node: Node offset of the node to operate on 205 * @fixup_node: Node offset of the matching local fixups node 206 * @delta: Offset to shift the phandles of 207 * 208 * overlay_update_local_nodes_references() update the phandles 209 * pointing to a node within the device tree overlay by adding a 210 * constant delta. 211 * 212 * This is mainly used as part of a device tree application process, 213 * where you want the device tree overlays phandles to not conflict 214 * with the ones from the base device tree before merging them. 215 * 216 * returns: 217 * 0 on success 218 * Negative error code on failure 219 */ 220 static int overlay_update_local_node_references(void *fdto, 221 int tree_node, 222 int fixup_node, 223 uint32_t delta) 224 { 225 int fixup_prop; 226 int fixup_child; 227 int ret; 228 229 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 230 const fdt32_t *fixup_val; 231 const char *tree_val; 232 const char *name; 233 int fixup_len; 234 int tree_len; 235 int i; 236 237 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 238 &name, &fixup_len); 239 if (!fixup_val) 240 return fixup_len; 241 242 if (fixup_len % sizeof(uint32_t)) 243 return -FDT_ERR_BADOVERLAY; 244 245 tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); 246 if (!tree_val) { 247 if (tree_len == -FDT_ERR_NOTFOUND) 248 return -FDT_ERR_BADOVERLAY; 249 250 return tree_len; 251 } 252 253 for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { 254 fdt32_t adj_val; 255 uint32_t poffset; 256 257 poffset = fdt32_to_cpu(fixup_val[i]); 258 259 /* 260 * phandles to fixup can be unaligned. 261 * 262 * Use a memcpy for the architectures that do 263 * not support unaligned accesses. 264 */ 265 memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); 266 267 adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); 268 269 ret = fdt_setprop_inplace_namelen_partial(fdto, 270 tree_node, 271 name, 272 strlen(name), 273 poffset, 274 &adj_val, 275 sizeof(adj_val)); 276 if (ret == -FDT_ERR_NOSPACE) 277 return -FDT_ERR_BADOVERLAY; 278 279 if (ret) 280 return ret; 281 } 282 } 283 284 fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 285 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, 286 NULL); 287 int tree_child; 288 289 tree_child = fdt_subnode_offset(fdto, tree_node, 290 fixup_child_name); 291 if (tree_child == -FDT_ERR_NOTFOUND) 292 return -FDT_ERR_BADOVERLAY; 293 if (tree_child < 0) 294 return tree_child; 295 296 ret = overlay_update_local_node_references(fdto, 297 tree_child, 298 fixup_child, 299 delta); 300 if (ret) 301 return ret; 302 } 303 304 return 0; 305 } 306 307 /** 308 * overlay_update_local_references - Adjust the overlay references 309 * @fdto: Device tree overlay blob 310 * @delta: Offset to shift the phandles of 311 * 312 * overlay_update_local_references() update all the phandles pointing 313 * to a node within the device tree overlay by adding a constant 314 * delta to not conflict with the base overlay. 315 * 316 * This is mainly used as part of a device tree application process, 317 * where you want the device tree overlays phandles to not conflict 318 * with the ones from the base device tree before merging them. 319 * 320 * returns: 321 * 0 on success 322 * Negative error code on failure 323 */ 324 static int overlay_update_local_references(void *fdto, uint32_t delta) 325 { 326 int fixups; 327 328 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 329 if (fixups < 0) { 330 /* There's no local phandles to adjust, bail out */ 331 if (fixups == -FDT_ERR_NOTFOUND) 332 return 0; 333 334 return fixups; 335 } 336 337 /* 338 * Update our local references from the root of the tree 339 */ 340 return overlay_update_local_node_references(fdto, 0, fixups, 341 delta); 342 } 343 344 /** 345 * overlay_fixup_one_phandle - Set an overlay phandle to the base one 346 * @fdt: Base Device Tree blob 347 * @fdto: Device tree overlay blob 348 * @symbols_off: Node offset of the symbols node in the base device tree 349 * @path: Path to a node holding a phandle in the overlay 350 * @path_len: number of path characters to consider 351 * @name: Name of the property holding the phandle reference in the overlay 352 * @name_len: number of name characters to consider 353 * @poffset: Offset within the overlay property where the phandle is stored 354 * @label: Label of the node referenced by the phandle 355 * 356 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to 357 * a node in the base device tree. 358 * 359 * This is part of the device tree overlay application process, when 360 * you want all the phandles in the overlay to point to the actual 361 * base dt nodes. 362 * 363 * returns: 364 * 0 on success 365 * Negative error code on failure 366 */ 367 static int overlay_fixup_one_phandle(void *fdt, void *fdto, 368 int symbols_off, 369 const char *path, uint32_t path_len, 370 const char *name, uint32_t name_len, 371 int poffset, const char *label) 372 { 373 const char *symbol_path; 374 uint32_t phandle; 375 fdt32_t phandle_prop; 376 int symbol_off, fixup_off; 377 int prop_len; 378 379 if (symbols_off < 0) 380 return symbols_off; 381 382 symbol_path = fdt_getprop(fdt, symbols_off, label, 383 &prop_len); 384 if (!symbol_path) 385 return prop_len; 386 387 symbol_off = fdt_path_offset(fdt, symbol_path); 388 if (symbol_off < 0) 389 return symbol_off; 390 391 phandle = fdt_get_phandle(fdt, symbol_off); 392 if (!phandle) 393 return -FDT_ERR_NOTFOUND; 394 395 fixup_off = fdt_path_offset_namelen(fdto, path, path_len); 396 if (fixup_off == -FDT_ERR_NOTFOUND) 397 return -FDT_ERR_BADOVERLAY; 398 if (fixup_off < 0) 399 return fixup_off; 400 401 phandle_prop = cpu_to_fdt32(phandle); 402 return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, 403 name, name_len, poffset, 404 &phandle_prop, 405 sizeof(phandle_prop)); 406 }; 407 408 /** 409 * overlay_fixup_phandle - Set an overlay phandle to the base one 410 * @fdt: Base Device Tree blob 411 * @fdto: Device tree overlay blob 412 * @symbols_off: Node offset of the symbols node in the base device tree 413 * @property: Property offset in the overlay holding the list of fixups 414 * 415 * overlay_fixup_phandle() resolves all the overlay phandles pointed 416 * to in a __fixups__ property, and updates them to match the phandles 417 * in use in the base device tree. 418 * 419 * This is part of the device tree overlay application process, when 420 * you want all the phandles in the overlay to point to the actual 421 * base dt nodes. 422 * 423 * returns: 424 * 0 on success 425 * Negative error code on failure 426 */ 427 static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, 428 int property) 429 { 430 const char *value; 431 const char *label; 432 int len; 433 434 value = fdt_getprop_by_offset(fdto, property, 435 &label, &len); 436 if (!value) { 437 if (len == -FDT_ERR_NOTFOUND) 438 return -FDT_ERR_INTERNAL; 439 440 return len; 441 } 442 443 do { 444 const char *path, *name, *fixup_end; 445 const char *fixup_str = value; 446 uint32_t path_len, name_len; 447 uint32_t fixup_len; 448 char *sep, *endptr; 449 int poffset, ret; 450 451 fixup_end = memchr(value, '\0', len); 452 if (!fixup_end) 453 return -FDT_ERR_BADOVERLAY; 454 fixup_len = fixup_end - fixup_str; 455 456 len -= fixup_len + 1; 457 value += fixup_len + 1; 458 459 path = fixup_str; 460 sep = memchr(fixup_str, ':', fixup_len); 461 if (!sep || *sep != ':') 462 return -FDT_ERR_BADOVERLAY; 463 464 path_len = sep - path; 465 if (path_len == (fixup_len - 1)) 466 return -FDT_ERR_BADOVERLAY; 467 468 fixup_len -= path_len + 1; 469 name = sep + 1; 470 sep = memchr(name, ':', fixup_len); 471 if (!sep || *sep != ':') 472 return -FDT_ERR_BADOVERLAY; 473 474 name_len = sep - name; 475 if (!name_len) 476 return -FDT_ERR_BADOVERLAY; 477 478 poffset = strtoul(sep + 1, &endptr, 10); 479 if ((*endptr != '\0') || (endptr <= (sep + 1))) 480 return -FDT_ERR_BADOVERLAY; 481 482 ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, 483 path, path_len, name, name_len, 484 poffset, label); 485 if (ret) 486 return ret; 487 } while (len > 0); 488 489 return 0; 490 } 491 492 /** 493 * overlay_fixup_phandles - Resolve the overlay phandles to the base 494 * device tree 495 * @fdt: Base Device Tree blob 496 * @fdto: Device tree overlay blob 497 * 498 * overlay_fixup_phandles() resolves all the overlay phandles pointing 499 * to nodes in the base device tree. 500 * 501 * This is one of the steps of the device tree overlay application 502 * process, when you want all the phandles in the overlay to point to 503 * the actual base dt nodes. 504 * 505 * returns: 506 * 0 on success 507 * Negative error code on failure 508 */ 509 static int overlay_fixup_phandles(void *fdt, void *fdto) 510 { 511 int fixups_off, symbols_off; 512 int property; 513 514 /* We can have overlays without any fixups */ 515 fixups_off = fdt_path_offset(fdto, "/__fixups__"); 516 if (fixups_off == -FDT_ERR_NOTFOUND) 517 return 0; /* nothing to do */ 518 if (fixups_off < 0) 519 return fixups_off; 520 521 /* And base DTs without symbols */ 522 symbols_off = fdt_path_offset(fdt, "/__symbols__"); 523 if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) 524 return symbols_off; 525 526 fdt_for_each_property_offset(property, fdto, fixups_off) { 527 int ret; 528 529 ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 530 if (ret) 531 return ret; 532 } 533 534 return 0; 535 } 536 537 /** 538 * overlay_apply_node - Merges a node into the base device tree 539 * @fdt: Base Device Tree blob 540 * @target: Node offset in the base device tree to apply the fragment to 541 * @fdto: Device tree overlay blob 542 * @node: Node offset in the overlay holding the changes to merge 543 * 544 * overlay_apply_node() merges a node into a target base device tree 545 * node pointed. 546 * 547 * This is part of the final step in the device tree overlay 548 * application process, when all the phandles have been adjusted and 549 * resolved and you just have to merge overlay into the base device 550 * tree. 551 * 552 * returns: 553 * 0 on success 554 * Negative error code on failure 555 */ 556 static int overlay_apply_node(void *fdt, int target, 557 void *fdto, int node) 558 { 559 int property; 560 int subnode; 561 562 fdt_for_each_property_offset(property, fdto, node) { 563 const char *name; 564 const void *prop; 565 int prop_len; 566 int ret; 567 568 prop = fdt_getprop_by_offset(fdto, property, &name, 569 &prop_len); 570 if (prop_len == -FDT_ERR_NOTFOUND) 571 return -FDT_ERR_INTERNAL; 572 if (prop_len < 0) 573 return prop_len; 574 575 ret = fdt_setprop(fdt, target, name, prop, prop_len); 576 if (ret) 577 return ret; 578 } 579 580 fdt_for_each_subnode(subnode, fdto, node) { 581 const char *name = fdt_get_name(fdto, subnode, NULL); 582 int nnode; 583 int ret; 584 585 nnode = fdt_add_subnode(fdt, target, name); 586 if (nnode == -FDT_ERR_EXISTS) { 587 nnode = fdt_subnode_offset(fdt, target, name); 588 if (nnode == -FDT_ERR_NOTFOUND) 589 return -FDT_ERR_INTERNAL; 590 } 591 592 if (nnode < 0) 593 return nnode; 594 595 ret = overlay_apply_node(fdt, nnode, fdto, subnode); 596 if (ret) 597 return ret; 598 } 599 600 return 0; 601 } 602 603 /** 604 * overlay_merge - Merge an overlay into its base device tree 605 * @fdt: Base Device Tree blob 606 * @fdto: Device tree overlay blob 607 * 608 * overlay_merge() merges an overlay into its base device tree. 609 * 610 * This is the next to last step in the device tree overlay application 611 * process, when all the phandles have been adjusted and resolved and 612 * you just have to merge overlay into the base device tree. 613 * 614 * returns: 615 * 0 on success 616 * Negative error code on failure 617 */ 618 static int overlay_merge(void *fdt, void *fdto) 619 { 620 int fragment; 621 622 fdt_for_each_subnode(fragment, fdto, 0) { 623 int overlay; 624 int target; 625 int ret; 626 627 /* 628 * Each fragments will have an __overlay__ node. If 629 * they don't, it's not supposed to be merged 630 */ 631 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 632 if (overlay == -FDT_ERR_NOTFOUND) 633 continue; 634 635 if (overlay < 0) 636 return overlay; 637 638 target = overlay_get_target(fdt, fdto, fragment, NULL); 639 if (target < 0) 640 return target; 641 642 ret = overlay_apply_node(fdt, target, fdto, overlay); 643 if (ret) 644 return ret; 645 } 646 647 return 0; 648 } 649 650 static int get_path_len(const void *fdt, int nodeoffset) 651 { 652 int len = 0, namelen; 653 const char *name; 654 655 FDT_RO_PROBE(fdt); 656 657 for (;;) { 658 name = fdt_get_name(fdt, nodeoffset, &namelen); 659 if (!name) 660 return namelen; 661 662 /* root? we're done */ 663 if (namelen == 0) 664 break; 665 666 nodeoffset = fdt_parent_offset(fdt, nodeoffset); 667 if (nodeoffset < 0) 668 return nodeoffset; 669 len += namelen + 1; 670 } 671 672 /* in case of root pretend it's "/" */ 673 if (len == 0) 674 len++; 675 return len; 676 } 677 678 /** 679 * overlay_symbol_update - Update the symbols of base tree after a merge 680 * @fdt: Base Device Tree blob 681 * @fdto: Device tree overlay blob 682 * 683 * overlay_symbol_update() updates the symbols of the base tree with the 684 * symbols of the applied overlay 685 * 686 * This is the last step in the device tree overlay application 687 * process, allowing the reference of overlay symbols by subsequent 688 * overlay operations. 689 * 690 * returns: 691 * 0 on success 692 * Negative error code on failure 693 */ 694 static int overlay_symbol_update(void *fdt, void *fdto) 695 { 696 int root_sym, ov_sym, prop, path_len, fragment, target; 697 int len, frag_name_len, ret, rel_path_len; 698 const char *s, *e; 699 const char *path; 700 const char *name; 701 const char *frag_name; 702 const char *rel_path; 703 const char *target_path; 704 char *buf; 705 void *p; 706 707 ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); 708 709 /* if no overlay symbols exist no problem */ 710 if (ov_sym < 0) 711 return 0; 712 713 root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); 714 715 /* it no root symbols exist we should create them */ 716 if (root_sym == -FDT_ERR_NOTFOUND) 717 root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); 718 719 /* any error is fatal now */ 720 if (root_sym < 0) 721 return root_sym; 722 723 /* iterate over each overlay symbol */ 724 fdt_for_each_property_offset(prop, fdto, ov_sym) { 725 path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); 726 if (!path) 727 return path_len; 728 729 /* verify it's a string property (terminated by a single \0) */ 730 if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) 731 return -FDT_ERR_BADVALUE; 732 733 /* keep end marker to avoid strlen() */ 734 e = path + path_len; 735 736 if (*path != '/') 737 return -FDT_ERR_BADVALUE; 738 739 /* get fragment name first */ 740 s = strchr(path + 1, '/'); 741 if (!s) { 742 /* Symbol refers to something that won't end 743 * up in the target tree */ 744 continue; 745 } 746 747 frag_name = path + 1; 748 frag_name_len = s - path - 1; 749 750 /* verify format; safe since "s" lies in \0 terminated prop */ 751 len = sizeof("/__overlay__/") - 1; 752 if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { 753 /* /<fragment-name>/__overlay__/<relative-subnode-path> */ 754 rel_path = s + len; 755 rel_path_len = e - rel_path - 1; 756 } else if ((e - s) == len 757 && (memcmp(s, "/__overlay__", len - 1) == 0)) { 758 /* /<fragment-name>/__overlay__ */ 759 rel_path = ""; 760 rel_path_len = 0; 761 } else { 762 /* Symbol refers to something that won't end 763 * up in the target tree */ 764 continue; 765 } 766 767 /* find the fragment index in which the symbol lies */ 768 ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 769 frag_name_len); 770 /* not found? */ 771 if (ret < 0) 772 return -FDT_ERR_BADOVERLAY; 773 fragment = ret; 774 775 /* an __overlay__ subnode must exist */ 776 ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); 777 if (ret < 0) 778 return -FDT_ERR_BADOVERLAY; 779 780 /* get the target of the fragment */ 781 ret = overlay_get_target(fdt, fdto, fragment, &target_path); 782 if (ret < 0) 783 return ret; 784 target = ret; 785 786 /* if we have a target path use */ 787 if (!target_path) { 788 ret = get_path_len(fdt, target); 789 if (ret < 0) 790 return ret; 791 len = ret; 792 } else { 793 len = strlen(target_path); 794 } 795 796 ret = fdt_setprop_placeholder(fdt, root_sym, name, 797 len + (len > 1) + rel_path_len + 1, &p); 798 if (ret < 0) 799 return ret; 800 801 if (!target_path) { 802 /* again in case setprop_placeholder changed it */ 803 ret = overlay_get_target(fdt, fdto, fragment, &target_path); 804 if (ret < 0) 805 return ret; 806 target = ret; 807 } 808 809 buf = p; 810 if (len > 1) { /* target is not root */ 811 if (!target_path) { 812 ret = fdt_get_path(fdt, target, buf, len + 1); 813 if (ret < 0) 814 return ret; 815 } else 816 memcpy(buf, target_path, len + 1); 817 818 } else 819 len--; 820 821 buf[len] = '/'; 822 memcpy(buf + len + 1, rel_path, rel_path_len); 823 buf[len + 1 + rel_path_len] = '\0'; 824 } 825 826 return 0; 827 } 828 829 int fdt_overlay_apply(void *fdt, void *fdto) 830 { 831 uint32_t delta; 832 int ret; 833 834 FDT_RO_PROBE(fdt); 835 FDT_RO_PROBE(fdto); 836 837 ret = fdt_find_max_phandle(fdt, &delta); 838 if (ret) 839 goto err; 840 841 ret = overlay_adjust_local_phandles(fdto, delta); 842 if (ret) 843 goto err; 844 845 ret = overlay_update_local_references(fdto, delta); 846 if (ret) 847 goto err; 848 849 ret = overlay_fixup_phandles(fdt, fdto); 850 if (ret) 851 goto err; 852 853 ret = overlay_merge(fdt, fdto); 854 if (ret) 855 goto err; 856 857 ret = overlay_symbol_update(fdt, fdto); 858 if (ret) 859 goto err; 860 861 /* 862 * The overlay has been damaged, erase its magic. 863 */ 864 fdt_set_magic(fdto, ~0); 865 866 return 0; 867 868 err: 869 /* 870 * The overlay might have been damaged, erase its magic. 871 */ 872 fdt_set_magic(fdto, ~0); 873 874 /* 875 * The base device tree might have been damaged, erase its 876 * magic. 877 */ 878 fdt_set_magic(fdt, ~0); 879 880 return ret; 881 } 882