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