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